viepilot 3.11.0 → 3.12.1

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,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ---
11
11
 
12
+ ## [3.12.1] - 2026-05-26
13
+ ### Fixed
14
+ - `bin/vp-tools.cjs` `check-update --silent`: OS session guard file (`/tmp/vp-update-check-{today}.done`) — subsequent skill invocations skip npm call entirely, exit with 0 stdout (0 tokens) (DEBT-003)
15
+ - `lib/viepilot-update.cjs`: reduce version cache TTL 24h → 6h for more timely update notices (DEBT-003)
16
+
17
+ ---
18
+
19
+ ## [3.12.0] - 2026-05-25
20
+ ### Changed
21
+ - `workflows/autonomous.md`: tracker-agent now rewrites Current State block (find-and-replace)
22
+ instead of appending — TRACKER.md stays ≤ 20 lines regardless of phase count (DEBT-002)
23
+ - `workflows/autonomous.md`: auto-compact size guard — if TRACKER.md > 400 lines, runs
24
+ `vp-tools tracker compact` before reading (DEBT-002)
25
+ - `workflows/autonomous.md`: Decision Log capped at 20 rows; older rows archived to TRACKER-HISTORY.md
26
+
27
+ ### Added
28
+ - `lib/tracker-compact.cjs`: compact() + rewriteCurrentState() — rescue tool for bloated TRACKER.md files
29
+ - `bin/vp-tools.cjs`: `tracker compact [--keep N]` subcommand — compact bloated TRACKER.md, archive history to TRACKER-HISTORY.md
30
+
31
+ ---
32
+
12
33
  ## [3.11.0] - 2026-05-25
13
34
 
14
35
  ### Added
package/bin/vp-tools.cjs CHANGED
@@ -1174,10 +1174,43 @@ ${colors.cyan}Examples:${colors.reset}
1174
1174
  const silent = args.includes('--silent');
1175
1175
  const json = args.includes('--json');
1176
1176
  const force = args.includes('--force');
1177
+
1178
+ // OS session guard — skip npm check if already done today (DEBT-003)
1179
+ if (!force && !json) {
1180
+ const _os = require('os');
1181
+ const _today = new Date().toISOString().split('T')[0];
1182
+ const _guardFile = require('path').join(_os.tmpdir(), `vp-update-check-${_today}.done`);
1183
+ if (fs.existsSync(_guardFile)) {
1184
+ try {
1185
+ const _g = JSON.parse(fs.readFileSync(_guardFile, 'utf8'));
1186
+ if (silent) {
1187
+ if (_g.updateAvailable) { process.stdout.write(_g.latest + '\n'); process.exit(1); }
1188
+ process.exit(0);
1189
+ }
1190
+ process.exit(0);
1191
+ } catch (_) { /* corrupt guard — fall through */ }
1192
+ }
1193
+ }
1194
+
1177
1195
  const { checkLatestVersion } = require('../lib/viepilot-update.cjs');
1178
1196
 
1179
1197
  checkLatestVersion({ force })
1180
1198
  .then(({ upToDate, installed, latest }) => {
1199
+ // Write OS session guard for subsequent skill inits (DEBT-003)
1200
+ if (silent || !json) {
1201
+ try {
1202
+ const _os2 = require('os');
1203
+ const _today2 = new Date().toISOString().split('T')[0];
1204
+ const _gf = require('path').join(_os2.tmpdir(), `vp-update-check-${_today2}.done`);
1205
+ fs.writeFileSync(_gf, JSON.stringify({
1206
+ updateAvailable: !upToDate,
1207
+ latest,
1208
+ installed,
1209
+ checkedAt: new Date().toISOString()
1210
+ }));
1211
+ } catch (_) { /* non-fatal */ }
1212
+ }
1213
+
1181
1214
  const has_update = !upToDate;
1182
1215
  if (json) {
1183
1216
  process.stdout.write(JSON.stringify({ installed, latest, has_update }) + '\n');
@@ -1389,6 +1422,70 @@ ${colors.cyan}Examples:${colors.reset}
1389
1422
  console.log();
1390
1423
  },
1391
1424
 
1425
+ /**
1426
+ * Compact bloated TRACKER.md and archive history (DEBT-002)
1427
+ * Usage: vp-tools tracker compact [--keep N] [--dry-run] [--path <file>]
1428
+ */
1429
+ tracker: (args) => {
1430
+ const sub = args[0];
1431
+
1432
+ if (!sub || sub === 'help') {
1433
+ console.log(`${colors.cyan}Usage:${colors.reset}
1434
+ vp-tools tracker compact [--keep N] [--dry-run] [--path <file>]
1435
+
1436
+ ${colors.cyan}Subcommands:${colors.reset}
1437
+ compact Compact bloated TRACKER.md, archive history
1438
+
1439
+ ${colors.cyan}Options:${colors.reset}
1440
+ --keep N Number of rows to keep (default: 5)
1441
+ --dry-run Preview changes without writing
1442
+ --path <file> Path to TRACKER.md (default: .viepilot/TRACKER.md)
1443
+
1444
+ ${colors.cyan}Examples:${colors.reset}
1445
+ ${colors.gray}$${colors.reset} vp-tools tracker compact
1446
+ ${colors.gray}$${colors.reset} vp-tools tracker compact --keep 10 --dry-run
1447
+ ${colors.gray}$${colors.reset} vp-tools tracker compact --path /path/to/TRACKER.md`);
1448
+ return;
1449
+ }
1450
+
1451
+ if (sub === 'compact') {
1452
+ // Parse options
1453
+ const keepIdx = args.indexOf('--keep');
1454
+ const keepN = keepIdx !== -1 ? parseInt(args[keepIdx + 1], 10) : 5;
1455
+ const isDryRun = args.includes('--dry-run');
1456
+
1457
+ const pathIdx = args.indexOf('--path');
1458
+ const argPath = pathIdx !== -1 ? args[pathIdx + 1] : null;
1459
+
1460
+ const trackerPath = argPath || path.join(process.cwd(), '.viepilot', 'TRACKER.md');
1461
+
1462
+ try {
1463
+ const { compact } = require(path.join(__dirname, '../lib/tracker-compact.cjs'));
1464
+ const result = compact(trackerPath, { keep: keepN, dryRun: isDryRun });
1465
+
1466
+ if (isDryRun) {
1467
+ console.log(`[dry-run] Would compact ${trackerPath}`);
1468
+ console.log(` Lines to remove: ${result.linesRemoved}`);
1469
+ console.log(` Rows to archive: ${result.rowsArchived}`);
1470
+ console.log(' No files written.');
1471
+ } else {
1472
+ console.log(formatSuccess(`Compacted ${trackerPath}`));
1473
+ console.log(` Lines removed: ${result.linesRemoved}`);
1474
+ console.log(` Rows archived: ${result.rowsArchived}`);
1475
+ console.log(` History file: ${result.historyFile}`);
1476
+ console.log(` Result: ${result.trackerLines} lines remaining`);
1477
+ }
1478
+ process.exit(0);
1479
+ } catch (err) {
1480
+ console.error(formatError('tracker compact error:', err.message));
1481
+ process.exit(1);
1482
+ }
1483
+ }
1484
+
1485
+ console.error(formatError(`Unknown tracker subcommand: ${sub}`, 'Use: compact'));
1486
+ process.exit(1);
1487
+ },
1488
+
1392
1489
  /**
1393
1490
  * Validate adapter capability requirements (FEAT-021 Phase 127)
1394
1491
  * Usage: vp-tools validate --adapter <id>
@@ -1618,6 +1715,20 @@ ${colors.cyan}Examples:${colors.reset}
1618
1715
  'vp-tools update --global --dry-run',
1619
1716
  ],
1620
1717
  },
1718
+ 'tracker': {
1719
+ usage: 'vp-tools tracker compact [--keep N] [--dry-run] [--path <file>]',
1720
+ description: 'Compact bloated TRACKER.md and archive history',
1721
+ options: [
1722
+ '--keep N: Number of rows to keep (default: 5)',
1723
+ '--dry-run: Preview changes without writing',
1724
+ '--path <file>: Path to TRACKER.md (default: .viepilot/TRACKER.md)',
1725
+ ],
1726
+ examples: [
1727
+ 'vp-tools tracker compact',
1728
+ 'vp-tools tracker compact --keep 10 --dry-run',
1729
+ 'vp-tools tracker compact --path /path/to/TRACKER.md',
1730
+ ],
1731
+ },
1621
1732
  };
1622
1733
 
1623
1734
  if (command && commandHelp[command]) {
@@ -1669,6 +1780,7 @@ ${colors.cyan}Commands:${colors.reset}
1669
1780
  ${colors.bold}persona${colors.reset} <op> Manage user personas (get|infer|list|set|auto-switch|context)
1670
1781
  ${colors.bold}detect-adapter${colors.reset} [--json] Detect active adapter (claude-code/cursor/antigravity/codex/copilot)
1671
1782
  ${colors.bold}validate${colors.reset} --adapter <id> Validate adapter capability requirements; exits 1 on critical gaps
1783
+ ${colors.bold}tracker${colors.reset} compact [--keep N] Compact bloated TRACKER.md, archive history
1672
1784
  ${colors.bold}help${colors.reset} [command] Show help (optionally for specific command)
1673
1785
 
1674
1786
  ${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,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 };
@@ -161,7 +161,7 @@ function runNpmUpdate(plan) {
161
161
  */
162
162
  async function checkLatestVersion(opts = {}) {
163
163
  const SILENT_RESULT = { upToDate: true, installed: '', latest: '' };
164
- const TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
164
+ const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours
165
165
 
166
166
  try {
167
167
  const cacheFile =
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viepilot",
3
- "version": "3.11.0",
3
+ "version": "3.12.1",
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": {
@@ -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",