viepilot 3.10.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 +33 -0
- package/bin/vp-tools.cjs +79 -0
- package/docs/skills-reference.md +36 -0
- package/lib/qa-router.cjs +72 -0
- package/lib/tracker-compact.cjs +124 -0
- package/package.json +1 -1
- package/skills/vp-qa/SKILL.md +306 -0
- package/workflows/autonomous.md +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,39 @@ 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
|
+
|
|
26
|
+
## [3.11.0] - 2026-05-25
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- ENH-100: New `/vp-qa` skill — scan-first QA agent team generator
|
|
30
|
+
- ENH-100: Phase 1 (Research) reads codebase structure, detects stack, samples source files,
|
|
31
|
+
reads stack reference docs, then LLM decides domains + agent count
|
|
32
|
+
- ENH-100: Phase 2 (Generate) — LLM writes agent files directly using Write tool;
|
|
33
|
+
content fully determined by research output (no templates)
|
|
34
|
+
- ENH-100: Adapter-specific output — Claude Code: `.claude/agents/` (multi-agent
|
|
35
|
+
orchestrator + subagents); Codex: `AGENTS.md` append; Cursor: `.cursor/rules/` MDC;
|
|
36
|
+
Antigravity: `.agents/skills/`; Copilot: `.github/agents/`
|
|
37
|
+
- ENH-100: `lib/qa-router.cjs` — adapter path mapping (resolveOutputSpec, expectedPaths)
|
|
38
|
+
- ENH-100: `agents/qa-templates/rules/` — stack reference docs for Node.js, Python,
|
|
39
|
+
Java, Go, Ruby (LLM reads during research phase for stack-specific anti-patterns)
|
|
40
|
+
- ENH-100: Generated `qa-orchestrator` creates `.viepilot/requests/BUG-{N}.md` entries
|
|
41
|
+
with AskUserQuestion accept/decline + `/vp-evolve` suggestion
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
12
45
|
## [3.10.0] - 2026-05-25
|
|
13
46
|
|
|
14
47
|
### 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,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the output spec for QA agent files given an adapter.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} adapterId - 'claude-code'|'cursor-agent'|'codex'|'antigravity'|'copilot'
|
|
8
|
+
* @param {string} projectRoot - Absolute path to the target project root
|
|
9
|
+
* @returns {object} outputSpec
|
|
10
|
+
*/
|
|
11
|
+
function resolveOutputSpec(adapterId, projectRoot) {
|
|
12
|
+
switch (adapterId) {
|
|
13
|
+
case 'claude-code':
|
|
14
|
+
return {
|
|
15
|
+
mode: 'multi-file',
|
|
16
|
+
dir: path.join(projectRoot, '.claude', 'agents'),
|
|
17
|
+
orchestratorFile: 'qa-orchestrator.md',
|
|
18
|
+
subagentSuffix: '-scanner.md',
|
|
19
|
+
description: '.claude/agents/ (Claude Code native agents)',
|
|
20
|
+
};
|
|
21
|
+
case 'cursor-agent':
|
|
22
|
+
return {
|
|
23
|
+
mode: 'single-file',
|
|
24
|
+
dir: path.join(projectRoot, '.cursor', 'rules'),
|
|
25
|
+
file: 'qa-checklist.mdc',
|
|
26
|
+
frontmatterRequired: true,
|
|
27
|
+
description: '.cursor/rules/qa-checklist.mdc (Cursor MDC rule)',
|
|
28
|
+
};
|
|
29
|
+
case 'codex':
|
|
30
|
+
return {
|
|
31
|
+
mode: 'append',
|
|
32
|
+
dir: projectRoot,
|
|
33
|
+
file: 'AGENTS.md',
|
|
34
|
+
sectionHeader: '## QA Agent Instructions',
|
|
35
|
+
description: 'AGENTS.md (Codex system instructions)',
|
|
36
|
+
};
|
|
37
|
+
case 'antigravity':
|
|
38
|
+
return {
|
|
39
|
+
mode: 'multi-file',
|
|
40
|
+
dir: path.join(projectRoot, '.agents', 'skills'),
|
|
41
|
+
orchestratorFile: 'qa-orchestrator/SKILL.md',
|
|
42
|
+
description: '.agents/skills/ (Antigravity skills)',
|
|
43
|
+
};
|
|
44
|
+
case 'copilot':
|
|
45
|
+
return {
|
|
46
|
+
mode: 'single-file',
|
|
47
|
+
dir: path.join(projectRoot, '.github', 'agents'),
|
|
48
|
+
file: 'qa-orchestrator.agent.md',
|
|
49
|
+
description: '.github/agents/ (Copilot custom agent)',
|
|
50
|
+
};
|
|
51
|
+
default:
|
|
52
|
+
// Fallback to claude-code
|
|
53
|
+
return resolveOutputSpec('claude-code', projectRoot);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* List the expected output file paths for a given adapter + domain list.
|
|
59
|
+
* Useful for pre-flight checks and test assertions.
|
|
60
|
+
*/
|
|
61
|
+
function expectedPaths(adapterId, projectRoot, domains = []) {
|
|
62
|
+
const spec = resolveOutputSpec(adapterId, projectRoot);
|
|
63
|
+
if (spec.mode === 'multi-file') {
|
|
64
|
+
return [
|
|
65
|
+
path.join(spec.dir, spec.orchestratorFile),
|
|
66
|
+
...domains.map(d => path.join(spec.dir, `qa-${d}${spec.subagentSuffix || '.md'}`)),
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
return [path.join(spec.dir, spec.file)];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { resolveOutputSpec, expectedPaths };
|
|
@@ -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
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vp-qa
|
|
3
|
+
description: "LLM-driven QA agent team generator — research codebase, generate context-aware QA scanning agents"
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<greeting>
|
|
8
|
+
## Invocation Banner
|
|
9
|
+
|
|
10
|
+
Output this banner as the **first** thing on every invocation — before questions, work, or any other output:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
14
|
+
VIEPILOT ► VP-QA v1.0.0 (fw 2.19.0)
|
|
15
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
16
|
+
```
|
|
17
|
+
</greeting>
|
|
18
|
+
|
|
19
|
+
<version_check>
|
|
20
|
+
## Version Update Check (ENH-072)
|
|
21
|
+
|
|
22
|
+
After displaying the greeting banner, run:
|
|
23
|
+
```bash
|
|
24
|
+
node "$HOME/.claude/viepilot/bin/vp-tools.cjs" check-update --silent
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**If exit code = 1** (update available — new version printed to stdout):
|
|
28
|
+
Display notice banner before any other output:
|
|
29
|
+
```
|
|
30
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
31
|
+
│ ✨ ViePilot {latest_version} available (installed: {current}) │
|
|
32
|
+
│ npm i -g viepilot && vp-tools install --target {adapter_id} │
|
|
33
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
34
|
+
```
|
|
35
|
+
Replace `{latest_version}` with stdout from the command, `{current}` with the installed
|
|
36
|
+
version, `{adapter_id}` with the active adapter (claude-code / cursor / antigravity / codex / copilot).
|
|
37
|
+
|
|
38
|
+
**If exit code = 0 or command unavailable**: silent, continue.
|
|
39
|
+
|
|
40
|
+
**Suppression rules:**
|
|
41
|
+
- `--no-update-check` flag on skill invocation → skip this step entirely
|
|
42
|
+
- `config.json` → `update.check: false` → skip this step entirely
|
|
43
|
+
- Show at most once per session (`update_check_done` session guard)
|
|
44
|
+
</version_check>
|
|
45
|
+
|
|
46
|
+
<persona_context>
|
|
47
|
+
## Persona Context Injection (ENH-073)
|
|
48
|
+
|
|
49
|
+
At skill start, run:
|
|
50
|
+
```bash
|
|
51
|
+
node "$HOME/.claude/viepilot/bin/vp-tools.cjs" persona auto-switch
|
|
52
|
+
node "$HOME/.claude/viepilot/bin/vp-tools.cjs" persona context
|
|
53
|
+
```
|
|
54
|
+
Inject the output as `## User Persona` context before any task execution.
|
|
55
|
+
Silent if command unavailable or errors.
|
|
56
|
+
</persona_context>
|
|
57
|
+
|
|
58
|
+
<adapter id="claude-code">
|
|
59
|
+
## A. Skill Invocation
|
|
60
|
+
- Skill được gọi khi user mention `vp-qa`, `/vp-qa`, "qa", "scan", "kiểm tra chất lượng"
|
|
61
|
+
- Treat all user text after the skill mention as `{{VP_ARGS}}`
|
|
62
|
+
|
|
63
|
+
## B. User Prompting
|
|
64
|
+
Prompt user conversationally with numbered list options.
|
|
65
|
+
|
|
66
|
+
## C. Tool Usage
|
|
67
|
+
Use Claude Code tools: `Bash` (shell), `Read` (file), `Edit` + `Write` (file write/patch),
|
|
68
|
+
`Grep` (search), `Glob` (file patterns), `LS`, `WebSearch`, `WebFetch`,
|
|
69
|
+
`Agent` (spawn subagent — multi-level nesting supported)
|
|
70
|
+
Interactive: `AskUserQuestion` (deferred — preload via ToolSearch before first call)
|
|
71
|
+
|
|
72
|
+
**Phase 1 research tools:**
|
|
73
|
+
- `Read` — parse .viepilot/PROJECT-META.md, STACKS.md, package.json, requirements.txt, etc.
|
|
74
|
+
- `Bash` — find backend directories, count files
|
|
75
|
+
- `Grep` — search for patterns in source code
|
|
76
|
+
|
|
77
|
+
**Phase 3 generation tools:**
|
|
78
|
+
- `Write` — create agent files directly (qa-orchestrator.md, qa-{domain}-scanner.md)
|
|
79
|
+
</adapter>
|
|
80
|
+
|
|
81
|
+
<adapter id="cursor-agent">
|
|
82
|
+
## A. Skill Invocation
|
|
83
|
+
Same trigger keywords as claude-code adapter.
|
|
84
|
+
|
|
85
|
+
## C. Tool Usage
|
|
86
|
+
Use Cursor tools: `run_terminal_cmd` (shell), `read_file` (read), `edit_file` (write/edit),
|
|
87
|
+
`grep_search` (search), `web_search`, `codebase_search`, `list_dir`, `file_search`
|
|
88
|
+
Interactive: text list fallback (AskQuestion available in Plan Mode only; Agent Mode = text)
|
|
89
|
+
Subagent: `/multitask` (user command, single-level only — not a callable tool)
|
|
90
|
+
MCP limit: 40 tools
|
|
91
|
+
</adapter>
|
|
92
|
+
|
|
93
|
+
<adapter id="antigravity">
|
|
94
|
+
## A. Skill Invocation
|
|
95
|
+
Same trigger keywords as claude-code adapter.
|
|
96
|
+
Skill discovery: LLM-driven (automatic, no slash command needed).
|
|
97
|
+
|
|
98
|
+
## C. Tool Usage
|
|
99
|
+
Use Antigravity tools: `shell` (cmd), `file_read`, `file_write`, MCP plugins
|
|
100
|
+
Interactive: text fallback (TUI-based; no formal AskUserQuestion)
|
|
101
|
+
Skill path: `.agents/skills/<skill>/SKILL.md` (project) or `~/.agents/skills/` (global)
|
|
102
|
+
</adapter>
|
|
103
|
+
|
|
104
|
+
<adapter id="codex">
|
|
105
|
+
## A. Skill Invocation
|
|
106
|
+
Same trigger keywords as claude-code adapter.
|
|
107
|
+
|
|
108
|
+
## C. Tool Usage
|
|
109
|
+
Use Codex tools: `container.exec` (sandboxed shell), `apply_patch` (file write), `web_search`
|
|
110
|
+
Interactive: text fallback (TUI Tab/Enter injection)
|
|
111
|
+
Config: `~/.codex/config.toml`
|
|
112
|
+
</adapter>
|
|
113
|
+
|
|
114
|
+
<adapter id="copilot">
|
|
115
|
+
## A. Skill Invocation
|
|
116
|
+
Same trigger keywords as claude-code adapter.
|
|
117
|
+
Discovery: User-driven (`@agent-name` in GitHub Copilot Chat).
|
|
118
|
+
|
|
119
|
+
## C. Tool Usage
|
|
120
|
+
Use Copilot tools: `runCommands` (shell), `read`/`readfile` (read), `edit`/`editFiles` (write),
|
|
121
|
+
`code_search`, `find_references`
|
|
122
|
+
Interactive: `askQuestions` (main agent only — NOT available in subagents; VS Code issue #293745)
|
|
123
|
+
Skill path: `.github/agents/<name>.agent.md`
|
|
124
|
+
</adapter>
|
|
125
|
+
|
|
126
|
+
<scope_policy>
|
|
127
|
+
## ViePilot Namespace Guard (BUG-004)
|
|
128
|
+
- Default mode: only use and reference `vp-*` skills in ViePilot workflows.
|
|
129
|
+
- External skills (`non vp-*`) are out of framework scope unless user explicitly opts in.
|
|
130
|
+
- If external skills appear in runtime context, ignore them and route with the closest built-in `vp-*` skill.
|
|
131
|
+
</scope_policy>
|
|
132
|
+
|
|
133
|
+
<implementation_routing_guard>
|
|
134
|
+
## Primary implementation lane (ENH-021)
|
|
135
|
+
|
|
136
|
+
- **`/vp-qa`** generates context-aware QA scanning agents for the current project.
|
|
137
|
+
- Output location determined by adapter via `lib/qa-router.cjs`.
|
|
138
|
+
- Generated agents invoke `qa-orchestrator` (claude-code) or execute sequential scans (others).
|
|
139
|
+
</implementation_routing_guard>
|
|
140
|
+
|
|
141
|
+
<objective>
|
|
142
|
+
Generate a team of QA scanning agents tailored to the project's stack, structure, and detected patterns.
|
|
143
|
+
|
|
144
|
+
**LLM-generates-directly approach:**
|
|
145
|
+
- Phase 1: LLM researches target codebase structure, stack, patterns, existing issues
|
|
146
|
+
- Phase 2: LLM determines output location via adapter routing (lib/qa-router.cjs)
|
|
147
|
+
- Phase 3: LLM writes agent files directly using Write tool (no template system)
|
|
148
|
+
- Phase 4: Show generated files and offer to run qa-orchestrator immediately (claude-code only)
|
|
149
|
+
|
|
150
|
+
**No templates:** Each agent's content is fully determined by research output. LLM tailors
|
|
151
|
+
scanning instructions to detected backend dirs, framework patterns, and known issues from `.viepilot/requests/`.
|
|
152
|
+
|
|
153
|
+
**After generation:** Generated agents (`qa-orchestrator` on claude-code or combined scanner on others)
|
|
154
|
+
will create `.viepilot/requests/BUG-{N}.md` for any QA issues found, and prompt user to accept/decline.
|
|
155
|
+
</objective>
|
|
156
|
+
|
|
157
|
+
<context>
|
|
158
|
+
Optional flags:
|
|
159
|
+
- `/vp-qa` — auto-detect adapter + stack, generate QA team
|
|
160
|
+
- `/vp-qa --run` — generate + immediately invoke qa-orchestrator
|
|
161
|
+
- `/vp-qa --focus sec` — bias research toward security domains
|
|
162
|
+
- `/vp-qa --focus perf` — bias research toward performance domains
|
|
163
|
+
- `/vp-qa --target <id>` — override adapter detection (claude-code / cursor-agent / antigravity / codex / copilot)
|
|
164
|
+
</context>
|
|
165
|
+
|
|
166
|
+
<process>
|
|
167
|
+
### Phase 1: Research (REQUIRED — do not skip)
|
|
168
|
+
|
|
169
|
+
Before writing any agent file, understand the project:
|
|
170
|
+
|
|
171
|
+
1. Read `.viepilot/PROJECT-META.md`, `STACKS.md`, `PROJECT-CONTEXT.md` (silent if missing)
|
|
172
|
+
2. Detect stack from: `package.json` / `pom.xml` / `go.mod` / `requirements.txt` / `Gemfile`
|
|
173
|
+
3. List backend directory structure: find `src/` `app/` `lib/` `services/` `api/` `routes/` (whichever exist)
|
|
174
|
+
4. Read 5-10 representative source files from backend dirs (understand patterns)
|
|
175
|
+
5. Count file sizes, service count, DB layer presence
|
|
176
|
+
6. Read `.viepilot/requests/` to list known existing issues (avoid duplicate reporting)
|
|
177
|
+
7. Read `agents/qa-templates/rules/{stack}.md` from project lib (if exists) for stack-specific patterns
|
|
178
|
+
|
|
179
|
+
**Build research summary:**
|
|
180
|
+
```
|
|
181
|
+
- projectName: string
|
|
182
|
+
- stack: (node / python / java / go / ruby / etc.)
|
|
183
|
+
- stackVersion: string (from version file)
|
|
184
|
+
- backendDirs: string[] (actual dirs found in project)
|
|
185
|
+
- detectedPatterns: string[] (anti-patterns spotted in sampling)
|
|
186
|
+
- recommendedDomains: string[] (scan areas relevant to this project)
|
|
187
|
+
- recommendedAgentCount: number (2 for small, 4-5 for large/complex)
|
|
188
|
+
- knownIssues: string[] (from .viepilot/requests/, avoid duplicates)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Phase 2: Determine Output Location
|
|
192
|
+
|
|
193
|
+
Use `lib/qa-router.cjs` to resolve adapter-specific output paths:
|
|
194
|
+
```
|
|
195
|
+
- claude-code → .claude/agents/
|
|
196
|
+
- cursor-agent → .cursor/rules/
|
|
197
|
+
- codex → AGENTS.md (single file, append mode)
|
|
198
|
+
- antigravity → .agents/skills/
|
|
199
|
+
- copilot → .github/agents/
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Call or reference lib/qa-router.cjs to map the current adapter to output directory.
|
|
203
|
+
|
|
204
|
+
### Phase 3: Generate Agent Files (LLM writes directly)
|
|
205
|
+
|
|
206
|
+
Based on research summary, generate agent content and write using Write tool.
|
|
207
|
+
|
|
208
|
+
**For claude-code (multi-agent):**
|
|
209
|
+
- Write `qa-orchestrator.md` — orchestrator that fan-outs to specialist subagents
|
|
210
|
+
- Name: "vp-qa orchestrator"
|
|
211
|
+
- Description: "Coordinate QA scanning across multiple domains for {projectName}"
|
|
212
|
+
- Model: claude-opus (or latest)
|
|
213
|
+
- maxTurns: 30
|
|
214
|
+
- Knows about backend dirs found, stack version, patterns to look for
|
|
215
|
+
- References each specialist subagent by name
|
|
216
|
+
- Receives domain reports, groups by severity
|
|
217
|
+
- Creates `.viepilot/requests/BUG-{N}.md` for accepted issues
|
|
218
|
+
- Uses AskUserQuestion for critical/high severity group acceptance
|
|
219
|
+
- Final AskUserQuestion: "N issues logged. Run /vp-evolve to plan fixes?"
|
|
220
|
+
|
|
221
|
+
- Write `qa-{domain}-scanner.md` for each recommended domain (e.g., qa-security-scanner, qa-performance-scanner)
|
|
222
|
+
- Name: "vp-qa {domain} scanner"
|
|
223
|
+
- Description: "Scan {projectName} for {domain} concerns"
|
|
224
|
+
- Model: claude-haiku-4 (efficient)
|
|
225
|
+
- maxTurns: 15
|
|
226
|
+
- Content references ACTUAL backend dirs found, ACTUAL patterns to look for
|
|
227
|
+
- Produces structured report of issues found in that domain
|
|
228
|
+
- Returns report to orchestrator
|
|
229
|
+
|
|
230
|
+
- Each file has correct YAML frontmatter (name, description, model, maxTurns, tools)
|
|
231
|
+
- Content NOT generic — references specific dirs, patterns, concerns found during Phase 1
|
|
232
|
+
|
|
233
|
+
**For other adapters (single-file mode):**
|
|
234
|
+
- Write one combined file with all domain instructions
|
|
235
|
+
- Sequential scanning procedure using that adapter's shell tools
|
|
236
|
+
- Same vp-request output format (BUG-{N}.md files)
|
|
237
|
+
- Single AskUserQuestion for all issues found at end
|
|
238
|
+
|
|
239
|
+
### Phase 4: AskUserQuestion (claude-code only)
|
|
240
|
+
|
|
241
|
+
After writing files, show what was generated:
|
|
242
|
+
```
|
|
243
|
+
Generated {N} agent files in {output_dir}:
|
|
244
|
+
- qa-orchestrator.md (coordinates scanning across domains)
|
|
245
|
+
- qa-security-scanner.md (scans for security concerns)
|
|
246
|
+
- qa-performance-scanner.md (scans for performance concerns)
|
|
247
|
+
... (other domain files)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**AskUserQuestion:**
|
|
251
|
+
```
|
|
252
|
+
question: "What would you like to do next?"
|
|
253
|
+
options:
|
|
254
|
+
- label: "Run QA scan now"
|
|
255
|
+
description: "Invoke qa-orchestrator immediately to start scanning"
|
|
256
|
+
- label: "Done for now"
|
|
257
|
+
description: "Exit — agents are ready in {output_dir}"
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**On selection:**
|
|
261
|
+
- "Run QA scan now": invoke qa-orchestrator immediately (or equivalent for non-claude-code adapters)
|
|
262
|
+
- "Done for now": print "QA agents ready in {output_dir}. Run qa-orchestrator to start scanning." and exit
|
|
263
|
+
|
|
264
|
+
**Text fallback (Cursor/Codex/Copilot/Antigravity):**
|
|
265
|
+
```
|
|
266
|
+
QA agents generated in {output_dir}
|
|
267
|
+
|
|
268
|
+
Next actions:
|
|
269
|
+
1. Review generated agent files
|
|
270
|
+
2. Run qa-orchestrator to start the QA scan
|
|
271
|
+
3. Adjust scanning domains as needed
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Generated qa-orchestrator Behavior (in target project, when run)
|
|
275
|
+
|
|
276
|
+
When user runs the generated `qa-orchestrator`:
|
|
277
|
+
1. Fan out to specialist subagents (claude-code) or scan sequentially (others)
|
|
278
|
+
2. Collect issue reports from each domain scanner
|
|
279
|
+
3. Group issues by severity (critical/high/medium/low)
|
|
280
|
+
4. For critical/high: AskUserQuestion per group (accept → create vp-request BUG-{N}, decline → skip)
|
|
281
|
+
5. For medium/low: one batch confirm
|
|
282
|
+
6. Create `.viepilot/requests/BUG-{N}.md` for each accepted issue
|
|
283
|
+
7. Final AskUserQuestion: "N issues logged. Run /vp-evolve to plan fixes?"
|
|
284
|
+
</process>
|
|
285
|
+
|
|
286
|
+
## Adapter Compatibility
|
|
287
|
+
|
|
288
|
+
### AskUserQuestion Tool (ENH-059)
|
|
289
|
+
After generation, use `AskUserQuestion` on Claude Code (terminal) for Phase 4 prompt.
|
|
290
|
+
|
|
291
|
+
| Adapter | Interactive Prompts | Notes |
|
|
292
|
+
|---------|---------------------|-------|
|
|
293
|
+
| Claude Code (terminal) | ✅ `AskUserQuestion` — **REQUIRED** at end of Phase 3 | Preload schema via ToolSearch first |
|
|
294
|
+
| Cursor / Codex / Copilot / Antigravity | ❌ Text fallback | Plain numbered list for next actions |
|
|
295
|
+
|
|
296
|
+
**Claude Code (terminal) — AUQ preload required (ENH-059):**
|
|
297
|
+
Before the first interactive prompt (Phase 4), call `ToolSearch` with `query: "select:AskUserQuestion"` to load the deferred tool schema. Only after `ToolSearch` succeeds can `AskUserQuestion` be invoked. If `ToolSearch` returns an error, fall back to plain-text numbered list for that session.
|
|
298
|
+
|
|
299
|
+
<success_criteria>
|
|
300
|
+
- [ ] Phase 1 research completed (read project structure, stack, patterns)
|
|
301
|
+
- [ ] Phase 2 output location determined via lib/qa-router.cjs
|
|
302
|
+
- [ ] Phase 3 agent files written using Write tool (content tailored to research output)
|
|
303
|
+
- [ ] Phase 4 AskUserQuestion shown (claude-code) or text fallback (others)
|
|
304
|
+
- [ ] Generated agents ready to execute qa-orchestrator
|
|
305
|
+
- [ ] Generated qa-orchestrator creates .viepilot/requests/BUG-{N}.md for found issues
|
|
306
|
+
</success_criteria>
|
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",
|