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 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}
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viepilot",
3
- "version": "3.10.0",
3
+ "version": "3.12.0",
4
4
  "description": "**Autonomous Vibe Coding Framework / Bộ khung phát triển tự động có kiểm soát**",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -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>
@@ -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: update-current-state. data: Last completed phase {N} — {phase_name}. version: {version}."
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",