viepilot 1.1.0 → 1.3.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 +4 -0
- package/README.md +8 -8
- package/bin/vp-tools.cjs +98 -2
- package/docs/README.md +3 -3
- package/docs/skills-reference.md +10 -8
- package/docs/user/features/autonomous-mode.md +23 -5
- package/lib/cli-shared.cjs +38 -0
- package/package.json +1 -1
- package/skills/vp-auto/SKILL.md +12 -3
- package/templates/phase/SUMMARY.md +2 -2
- package/templates/phase/TASK.md +3 -2
- package/workflows/audit.md +5 -4
- package/workflows/autonomous.md +33 -7
- package/workflows/rollback.md +8 -7
package/CHANGELOG.md
CHANGED
|
@@ -16,10 +16,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
16
|
|
|
17
17
|
### Fixed
|
|
18
18
|
|
|
19
|
+
- **M1.19 / Phase 23 (BUG-003) completed** — enforced deterministic git persistence gates for `/vp-auto`: PASS transitions now require clean worktree, configured upstream, and zero unpushed commits (via `vp-tools git-persistence --strict` in workflow).
|
|
20
|
+
- **M1.18 / Phase 22 (BUG-002) completed** — introduced project-scoped checkpoint tags (`{project}-vp-p...`) and kept backward compatibility with legacy `vp-p...` tags for list/rollback flows.
|
|
19
21
|
- **CI coverage** — Jest chỉ instrument process hiện tại; test CLI qua `spawnSync` khiến `bin/vp-tools.cjs` báo **0%**. Đã tách `lib/cli-shared.cjs` (validators, `findProjectRoot`, Levenshtein) và đặt `collectCoverageFrom` trên file đó; bổ sung test in-process + `require.main === module` gate cho CLI; `install.sh` / `dev-install.sh` cài kèm `lib/`.
|
|
20
22
|
|
|
21
23
|
### Documentation
|
|
22
24
|
|
|
25
|
+
- `README.md`, `docs/README.md` — refreshed framework version, skills/commands/test counts, and index notes after M1.18 checkpoint-tag rollout.
|
|
26
|
+
- `workflows/autonomous.md`, `skills/vp-auto/SKILL.md`, `docs/user/features/autonomous-mode.md`, `docs/skills-reference.md` — documented and standardized git persistence gate behavior for `/vp-auto`.
|
|
23
27
|
- `README.md`, `docs/user/quick-start.md` — updated install wizard controls and uninstall command examples.
|
|
24
28
|
- `README.md`, `docs/troubleshooting.md`, `docs/user/quick-start.md` — documented README metric sync flow, `cloc` fallback/install guidance, and maintainer usage.
|
|
25
29
|
- `docs/troubleshooting.md` — added selector TTY fallback guidance and uninstall/reinstall recovery flow for legacy symlink installs.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Autonomous Vibe Coding Framework / Bộ khung phát triển tự động có kiểm soát**
|
|
4
4
|
|
|
5
|
-
[](CHANGELOG.md)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](#skills-reference)
|
|
8
8
|
[](#workflows)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](tests/)
|
|
11
11
|
[](https://github.com/0-CODE/viepilot)
|
|
12
12
|
|
|
13
|
-
**Versioning:** Shield **
|
|
13
|
+
**Versioning:** Shield **1.2.0** is the **ViePilot framework SemVer** tracked in `.viepilot/TRACKER.md` and `CHANGELOG.md`. The npm `package.json` field `version` (**1.2.0**) is the Node package identifier for this repo and may differ; use the framework version for milestone releases and docs.
|
|
14
14
|
|
|
15
15
|
ViePilot là bộ skill framework cho phép AI assistant (Claude, GPT, etc.) phát triển dự án một cách **tự động**, **có kiểm soát**, và **có thể khôi phục**. Thiết kế theo các tiêu chuẩn chuyên nghiệp: Semantic Versioning, Conventional Commits, Keep a Changelog.
|
|
16
16
|
|
|
@@ -48,14 +48,14 @@ Nếu ViePilot giúp ích cho bạn, bạn có thể ủng hộ một ly cafe:
|
|
|
48
48
|
| Project Templates | 11 | AI-GUIDE, ARCHITECTURE, README, SYSTEM-RULES, etc. |
|
|
49
49
|
| Phase Templates | 5 | SPEC, PHASE-STATE, TASK, VERIFICATION, SUMMARY |
|
|
50
50
|
| CLI Tools | 2 | vp-tools.cjs (**13** commands) + viepilot.cjs (guided installer) |
|
|
51
|
-
| Test Files |
|
|
51
|
+
| Test Files | 4 | Jest unit + integration + AI compatibility + README metrics tests (231 tests) |
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
55
55
|
## Độ hoàn thiện / Completion Status
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
Tổng thể / Overall: ████████████████████ 100% 🎉 M1.
|
|
58
|
+
Tổng thể / Overall: ████████████████████ 100% 🎉 M1.18 roadmap phases ✅ (v1.2.0)
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
| Lĩnh vực / Area | Trạng thái | Chi tiết |
|
|
@@ -184,7 +184,7 @@ Tổng thể / Overall: ██████████████████
|
|
|
184
184
|
| **Workflows** | Step-by-step XML-like process definitions |
|
|
185
185
|
| **CLI** | Node.js (vp-tools.cjs, viepilot.cjs) |
|
|
186
186
|
| **State** | JSON (HANDOFF.json) + Markdown (TRACKER.md) |
|
|
187
|
-
| **Version Control** | Git tags for checkpoints (vp-p{N}-t{M}) |
|
|
187
|
+
| **Version Control** | Git tags for checkpoints (`{project}-vp-p{N}-t{M}`, legacy `vp-p{N}-t{M}` supported) |
|
|
188
188
|
|
|
189
189
|
---
|
|
190
190
|
|
|
@@ -386,9 +386,9 @@ viepilot/
|
|
|
386
386
|
│ └── cli-shared.cjs # Validators, project root, Levenshtein helpers
|
|
387
387
|
│
|
|
388
388
|
├── bin/ # CLI tools
|
|
389
|
-
│ └── vp-tools.cjs #
|
|
389
|
+
│ └── vp-tools.cjs # 14 commands (requires ../lib/cli-shared.cjs)
|
|
390
390
|
│
|
|
391
|
-
├── tests/ # Test suite (
|
|
391
|
+
├── tests/ # Test suite (231 tests)
|
|
392
392
|
│ ├── unit/ # Unit tests
|
|
393
393
|
│ │ ├── validators.test.js # CLI subprocess + in-process coverage tests
|
|
394
394
|
│ │ └── ai-provider-compat.test.js # 142 AI compat tests
|
|
@@ -488,7 +488,7 @@ your-project/
|
|
|
488
488
|
| [Getting Started](docs/getting-started.md) | Hướng dẫn bắt đầu / Quick start guide |
|
|
489
489
|
| [Quick Start (User)](docs/user/quick-start.md) | 5-minute guide |
|
|
490
490
|
| [Skills Reference](docs/skills-reference.md) | Chi tiết từng skill / Detailed skill docs |
|
|
491
|
-
| [CLI Reference](docs/dev/cli-reference.md) | vp-tools
|
|
491
|
+
| [CLI Reference](docs/dev/cli-reference.md) | vp-tools 14 commands |
|
|
492
492
|
| [Advanced Usage](docs/advanced-usage.md) | Power user features |
|
|
493
493
|
| [Troubleshooting](docs/troubleshooting.md) | Common issues & fixes |
|
|
494
494
|
| [Architecture](docs/dev/architecture.md) | System design |
|
package/bin/vp-tools.cjs
CHANGED
|
@@ -19,6 +19,8 @@ const {
|
|
|
19
19
|
levenshteinDistance,
|
|
20
20
|
findProjectRoot,
|
|
21
21
|
VIEPILOT_DIR,
|
|
22
|
+
getCheckpointTagPrefix,
|
|
23
|
+
isCheckpointTag,
|
|
22
24
|
} = require(path.join(__dirname, '../lib/cli-shared.cjs'));
|
|
23
25
|
|
|
24
26
|
// ============================================================================
|
|
@@ -570,10 +572,10 @@ const commands = {
|
|
|
570
572
|
const { execSync } = require('child_process');
|
|
571
573
|
|
|
572
574
|
try {
|
|
573
|
-
const tags = execSync('git tag
|
|
575
|
+
const tags = execSync('git tag --sort=-creatordate', {
|
|
574
576
|
cwd: projectRoot,
|
|
575
577
|
encoding: 'utf8'
|
|
576
|
-
}).trim().split('\n').filter(t => t);
|
|
578
|
+
}).trim().split('\n').filter(t => t).filter(isCheckpointTag);
|
|
577
579
|
|
|
578
580
|
if (tags.length === 0) {
|
|
579
581
|
console.log(formatWarning('No checkpoints found'));
|
|
@@ -616,6 +618,82 @@ const commands = {
|
|
|
616
618
|
}
|
|
617
619
|
},
|
|
618
620
|
|
|
621
|
+
/**
|
|
622
|
+
* Output deterministic project-scoped checkpoint tag prefix
|
|
623
|
+
*/
|
|
624
|
+
'tag-prefix': (args) => {
|
|
625
|
+
const projectCheck = validators.requireProjectRoot();
|
|
626
|
+
validateArgs([projectCheck]);
|
|
627
|
+
const raw = args.includes('--raw');
|
|
628
|
+
const prefix = getCheckpointTagPrefix(projectCheck.value);
|
|
629
|
+
if (raw) {
|
|
630
|
+
console.log(prefix);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
console.log(formatInfo(`Checkpoint tag prefix: ${colors.bold}${prefix}${colors.reset}`));
|
|
634
|
+
console.log(JSON.stringify({ prefix }));
|
|
635
|
+
},
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Validate git persistence readiness for PASS transitions
|
|
639
|
+
*/
|
|
640
|
+
'git-persistence': (args) => {
|
|
641
|
+
const projectCheck = validators.requireProjectRoot();
|
|
642
|
+
validateArgs([projectCheck]);
|
|
643
|
+
const projectRoot = projectCheck.value;
|
|
644
|
+
const strict = args.includes('--strict');
|
|
645
|
+
const { execSync } = require('child_process');
|
|
646
|
+
|
|
647
|
+
let cleanWorktree = false;
|
|
648
|
+
let upstreamConfigured = false;
|
|
649
|
+
let aheadCount = null;
|
|
650
|
+
let branch = '';
|
|
651
|
+
|
|
652
|
+
try {
|
|
653
|
+
branch = execSync('git branch --show-current', { cwd: projectRoot, encoding: 'utf8' }).trim();
|
|
654
|
+
} catch (_e) {
|
|
655
|
+
branch = '';
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
try {
|
|
659
|
+
const status = execSync('git status --porcelain', { cwd: projectRoot, encoding: 'utf8' }).trim();
|
|
660
|
+
cleanWorktree = status.length === 0;
|
|
661
|
+
} catch (_e) {
|
|
662
|
+
cleanWorktree = false;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
try {
|
|
666
|
+
execSync('git rev-parse --abbrev-ref --symbolic-full-name @{u}', { cwd: projectRoot, encoding: 'utf8' });
|
|
667
|
+
upstreamConfigured = true;
|
|
668
|
+
} catch (_e) {
|
|
669
|
+
upstreamConfigured = false;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (upstreamConfigured) {
|
|
673
|
+
try {
|
|
674
|
+
const output = execSync('git rev-list --count @{u}..HEAD', { cwd: projectRoot, encoding: 'utf8' }).trim();
|
|
675
|
+
aheadCount = parseInt(output, 10);
|
|
676
|
+
} catch (_e) {
|
|
677
|
+
aheadCount = null;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const readyForPersistedPass = cleanWorktree && upstreamConfigured && aheadCount === 0;
|
|
682
|
+
const result = {
|
|
683
|
+
branch,
|
|
684
|
+
clean_worktree: cleanWorktree,
|
|
685
|
+
upstream_configured: upstreamConfigured,
|
|
686
|
+
ahead_count: aheadCount,
|
|
687
|
+
ready_for_persisted_pass: readyForPersistedPass,
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
console.log(JSON.stringify(result, null, 2));
|
|
691
|
+
|
|
692
|
+
if (strict && !readyForPersistedPass) {
|
|
693
|
+
process.exit(1);
|
|
694
|
+
}
|
|
695
|
+
},
|
|
696
|
+
|
|
619
697
|
/**
|
|
620
698
|
* Check for potential conflicts
|
|
621
699
|
*/
|
|
@@ -803,6 +881,22 @@ const commands = {
|
|
|
803
881
|
'vp-tools version bump minor',
|
|
804
882
|
],
|
|
805
883
|
},
|
|
884
|
+
'tag-prefix': {
|
|
885
|
+
usage: 'vp-tools tag-prefix [--raw]',
|
|
886
|
+
description: 'Return deterministic project-scoped checkpoint tag prefix',
|
|
887
|
+
examples: [
|
|
888
|
+
'vp-tools tag-prefix',
|
|
889
|
+
'vp-tools tag-prefix --raw',
|
|
890
|
+
],
|
|
891
|
+
},
|
|
892
|
+
'git-persistence': {
|
|
893
|
+
usage: 'vp-tools git-persistence [--strict]',
|
|
894
|
+
description: 'Check if commit/push persistence gate is satisfied',
|
|
895
|
+
examples: [
|
|
896
|
+
'vp-tools git-persistence',
|
|
897
|
+
'vp-tools git-persistence --strict',
|
|
898
|
+
],
|
|
899
|
+
},
|
|
806
900
|
};
|
|
807
901
|
|
|
808
902
|
if (command && commandHelp[command]) {
|
|
@@ -839,6 +933,8 @@ ${colors.cyan}Commands:${colors.reset}
|
|
|
839
933
|
${colors.bold}reset${colors.reset} <target> [-f] Reset task/phase/all state (interactive)
|
|
840
934
|
${colors.bold}clean${colors.reset} [-f] [--dry-run] Clean generated files (interactive)
|
|
841
935
|
${colors.bold}checkpoints${colors.reset} List all ViePilot checkpoints (git tags)
|
|
936
|
+
${colors.bold}tag-prefix${colors.reset} [--raw] Show project-scoped checkpoint prefix
|
|
937
|
+
${colors.bold}git-persistence${colors.reset} [--strict] Check commit/push persistence readiness
|
|
842
938
|
${colors.bold}conflicts${colors.reset} Check for potential conflicts
|
|
843
939
|
${colors.bold}save-state${colors.reset} Save current state for precise resume
|
|
844
940
|
${colors.bold}help${colors.reset} [command] Show help (optionally for specific command)
|
package/docs/README.md
CHANGED
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
|----------|-------------|
|
|
54
54
|
| [Getting Started](getting-started.md) | Installation and first steps |
|
|
55
55
|
| [Getting Started (dev entry)](dev/getting-started.md) | Short link into dev guide |
|
|
56
|
-
| [CLI Reference](dev/cli-reference.md) | All
|
|
56
|
+
| [CLI Reference](dev/cli-reference.md) | All 14 `vp-tools` commands with examples |
|
|
57
57
|
| [Architecture](dev/architecture.md) | System layers, data flow, design decisions |
|
|
58
58
|
| [UI Components Library](dev/ui-components-library.md) | Curation taxonomy, storage contract, reuse flow |
|
|
59
59
|
| [Contributing](dev/contributing.md) | How to add skills, workflows, CLI commands |
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
| Document | Description |
|
|
68
68
|
|----------|-------------|
|
|
69
|
-
| [Skills Reference](skills-reference.md) | All
|
|
69
|
+
| [Skills Reference](skills-reference.md) | All 14 skills with flags and examples |
|
|
70
70
|
| [Advanced Usage](advanced-usage.md) | Power user features and patterns |
|
|
71
71
|
|
|
72
72
|
---
|
|
@@ -122,4 +122,4 @@
|
|
|
122
122
|
|
|
123
123
|
---
|
|
124
124
|
|
|
125
|
-
*Last updated: 2026-03-31 — ViePilot framework
|
|
125
|
+
*Last updated: 2026-03-31 — ViePilot framework v1.2.0 (see `.viepilot/TRACKER.md`); project-scoped checkpoint tags delivered.*
|
package/docs/skills-reference.md
CHANGED
|
@@ -96,8 +96,9 @@ For each phase:
|
|
|
96
96
|
2. Create git tag
|
|
97
97
|
3. Execute implementation
|
|
98
98
|
4. Verify results
|
|
99
|
-
5.
|
|
100
|
-
6.
|
|
99
|
+
5. Enforce git persistence gate (`vp-tools git-persistence --strict`)
|
|
100
|
+
6. Handle outcome (pass/fail)
|
|
101
|
+
7. Update state
|
|
101
102
|
Mark phase complete
|
|
102
103
|
```
|
|
103
104
|
|
|
@@ -109,9 +110,10 @@ AI pauses for user input when:
|
|
|
109
110
|
- Blocker encountered
|
|
110
111
|
|
|
111
112
|
### Git Tags
|
|
112
|
-
- `vp-p{phase}-t{task}` - Task started
|
|
113
|
-
- `vp-p{phase}-t{task}-done` - Task completed
|
|
114
|
-
- `vp-p{phase}-complete` - Phase completed
|
|
113
|
+
- `{project}-vp-p{phase}-t{task}` - Task started
|
|
114
|
+
- `{project}-vp-p{phase}-t{task}-done` - Task completed
|
|
115
|
+
- `{project}-vp-p{phase}-complete` - Phase completed
|
|
116
|
+
- Legacy `vp-p...` tags are still accepted for compatibility
|
|
115
117
|
|
|
116
118
|
---
|
|
117
119
|
|
|
@@ -337,9 +339,9 @@ CHANGELOG.md (updated)
|
|
|
337
339
|
### Checkpoint Types
|
|
338
340
|
| Tag Pattern | Created By | Meaning |
|
|
339
341
|
|-------------|------------|---------|
|
|
340
|
-
| `vp-p{N}-t{M}` | vp-auto | Task started |
|
|
341
|
-
| `vp-p{N}-t{M}-done` | vp-auto | Task completed |
|
|
342
|
-
| `vp-p{N}-complete` | vp-auto | Phase completed |
|
|
342
|
+
| `{project}-vp-p{N}-t{M}` | vp-auto | Task started |
|
|
343
|
+
| `{project}-vp-p{N}-t{M}-done` | vp-auto | Task completed |
|
|
344
|
+
| `{project}-vp-p{N}-complete` | vp-auto | Phase completed |
|
|
343
345
|
| `v{semver}` | vp-auto | Version release |
|
|
344
346
|
|
|
345
347
|
### Safety Guarantees
|
|
@@ -13,11 +13,12 @@ Autonomous mode điều phối **toàn bộ** phase và task theo `workflows/aut
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Mỗi task:
|
|
16
|
-
1. Tạo git checkpoint tag (`vp-p{N}-t{T}`)
|
|
16
|
+
1. Tạo git checkpoint tag (`{project}-vp-p{N}-t{T}`)
|
|
17
17
|
2. Implement theo acceptance criteria
|
|
18
18
|
3. Verify (automated + manual nếu cần)
|
|
19
19
|
4. Commit với conventional commit message
|
|
20
|
-
5. Tạo done tag (`vp-p{N}-t{T}-done`)
|
|
20
|
+
5. Tạo done tag (`{project}-vp-p{N}-t{T}-done`)
|
|
21
|
+
6. Pass Git persistence gate (clean + pushed) trước khi mark done
|
|
21
22
|
|
|
22
23
|
## Flags
|
|
23
24
|
|
|
@@ -82,20 +83,37 @@ Trước khi mark task done, ViePilot kiểm tra:
|
|
|
82
83
|
|
|
83
84
|
Nếu bất kỳ gate nào fail → control point.
|
|
84
85
|
|
|
86
|
+
## Git Persistence Gate (BUG-003)
|
|
87
|
+
|
|
88
|
+
Trước khi `/vp-auto` được phép mark task/phase là PASS:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
node bin/vp-tools.cjs git-persistence --strict
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Gate chỉ PASS khi:
|
|
95
|
+
- Working tree sạch (không còn thay đổi chưa commit)
|
|
96
|
+
- Nhánh hiện tại có upstream
|
|
97
|
+
- Không còn commit local chưa push (`ahead_count = 0`)
|
|
98
|
+
|
|
99
|
+
Nếu fail, workflow phải vào control point và **không được** cập nhật state sang `done/complete`.
|
|
100
|
+
|
|
85
101
|
## Checkpoints
|
|
86
102
|
|
|
87
103
|
Mỗi task tạo 2 git tags:
|
|
88
104
|
|
|
89
105
|
```bash
|
|
90
|
-
vp-p2-t3 # Bắt đầu task 3 của phase 2
|
|
91
|
-
vp-p2-t3-done # Hoàn thành task 3 của phase 2
|
|
106
|
+
viepilot-vp-p2-t3 # Bắt đầu task 3 của phase 2
|
|
107
|
+
viepilot-vp-p2-t3-done # Hoàn thành task 3 của phase 2
|
|
92
108
|
```
|
|
93
109
|
|
|
94
110
|
Khi phase complete:
|
|
95
111
|
```bash
|
|
96
|
-
vp-p2-complete # Phase 2 hoàn thành
|
|
112
|
+
viepilot-vp-p2-complete # Phase 2 hoàn thành
|
|
97
113
|
```
|
|
98
114
|
|
|
115
|
+
Legacy tags `vp-p...` vẫn được hỗ trợ khi list/rollback để tương thích dự án cũ.
|
|
116
|
+
|
|
99
117
|
Xem tất cả checkpoints:
|
|
100
118
|
```bash
|
|
101
119
|
vp-tools checkpoints
|
package/lib/cli-shared.cjs
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
8
9
|
|
|
9
10
|
const VIEPILOT_DIR = '.viepilot';
|
|
10
11
|
|
|
@@ -19,6 +20,39 @@ function findProjectRoot() {
|
|
|
19
20
|
return null;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
function normalizeTagPart(value) {
|
|
24
|
+
return String(value || '')
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
27
|
+
.replace(/^-+|-+$/g, '')
|
|
28
|
+
.replace(/-{2,}/g, '-');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getProjectSlug(root = findProjectRoot()) {
|
|
32
|
+
if (!root) return 'project';
|
|
33
|
+
try {
|
|
34
|
+
const gitTop = execSync('git rev-parse --show-toplevel', { cwd: root, encoding: 'utf8' }).trim();
|
|
35
|
+
const repoName = path.basename(gitTop);
|
|
36
|
+
const normalizedRepo = normalizeTagPart(repoName);
|
|
37
|
+
if (normalizedRepo) return normalizedRepo;
|
|
38
|
+
} catch (_e) {
|
|
39
|
+
// fallback to directory name below
|
|
40
|
+
}
|
|
41
|
+
return normalizeTagPart(path.basename(root)) || 'project';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getCheckpointTagPrefix(root = findProjectRoot()) {
|
|
45
|
+
return `${getProjectSlug(root)}-vp`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isCheckpointTag(tag) {
|
|
49
|
+
const value = String(tag || '');
|
|
50
|
+
return /^vp-p\d+-(?:t\d+(?:-done)?|complete)$/.test(value)
|
|
51
|
+
|| /^[a-z0-9][a-z0-9-]*-vp-p\d+-(?:t\d+(?:-done)?|complete)$/.test(value)
|
|
52
|
+
|| /^vp-backup-\d{8}-\d{6}$/.test(value)
|
|
53
|
+
|| /^[a-z0-9][a-z0-9-]*-vp-backup-\d{8}-\d{6}$/.test(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
22
56
|
const validators = {
|
|
23
57
|
isPositiveInteger(value, name = 'value') {
|
|
24
58
|
const num = parseInt(value, 10);
|
|
@@ -103,6 +137,10 @@ function levenshteinDistance(a, b) {
|
|
|
103
137
|
module.exports = {
|
|
104
138
|
VIEPILOT_DIR,
|
|
105
139
|
findProjectRoot,
|
|
140
|
+
normalizeTagPart,
|
|
141
|
+
getProjectSlug,
|
|
142
|
+
getCheckpointTagPrefix,
|
|
143
|
+
isCheckpointTag,
|
|
106
144
|
validators,
|
|
107
145
|
levenshteinDistance,
|
|
108
146
|
};
|
package/package.json
CHANGED
package/skills/vp-auto/SKILL.md
CHANGED
|
@@ -35,6 +35,15 @@ Pauses at control points:
|
|
|
35
35
|
- `CHANGELOG.md` (if feature/fix)
|
|
36
36
|
- `.viepilot/ROADMAP.md` when task completion changes phase progress/status
|
|
37
37
|
|
|
38
|
+
**Git persistence gate before PASS (BUG-003):**
|
|
39
|
+
- Task/phase cannot be marked PASS if git is not durably persisted.
|
|
40
|
+
- Required checks:
|
|
41
|
+
- `git status --porcelain` must be empty
|
|
42
|
+
- upstream branch must exist (`git rev-parse ... @{u}`)
|
|
43
|
+
- no unpushed commits (`git rev-list --count @{u}..HEAD` equals `0`)
|
|
44
|
+
- Recommended single check: `node bin/vp-tools.cjs git-persistence --strict`
|
|
45
|
+
- On failure: route to control point (retry commit/push, rollback, or stop).
|
|
46
|
+
|
|
38
47
|
**Mandatory task decomposition before implementation:**
|
|
39
48
|
- Objective with concrete expected outcome
|
|
40
49
|
- Exact file paths to create/modify
|
|
@@ -47,7 +56,7 @@ If required task details are missing, do not implement until task contract is re
|
|
|
47
56
|
**Doc-first gate before implementation (BUG-001):**
|
|
48
57
|
- After contract validation and **before** any deliverable code/doc edits: the task `.md` MUST hold a real written plan (`Paths` + `File-Level Plan` or bullet **Implementation Notes**—no bare `{{PLACEHOLDER}}` rows).
|
|
49
58
|
- `PHASE-STATE.md` MUST show the task `in_progress` **before** the first implementation commit for that task.
|
|
50
|
-
- **Do not** create `vp-p{phase}-t{task}` or edit shipping files until both are satisfied (read-only exploration and editing the task file to record the plan are allowed).
|
|
59
|
+
- **Do not** create `{projectPrefix}-vp-p{phase}-t{task}` or edit shipping files until both are satisfied (read-only exploration and editing the task file to record the plan are allowed).
|
|
51
60
|
|
|
52
61
|
**Preflight before each task implementation:**
|
|
53
62
|
- Read `.viepilot/STACKS.md` (if exists)
|
|
@@ -132,7 +141,7 @@ Stack preflight:
|
|
|
132
141
|
1. Validate task contract (`workflows/autonomous.md`).
|
|
133
142
|
2. Record plan in task file; set task `in_progress` in `PHASE-STATE.md`.
|
|
134
143
|
3. Stack preflight.
|
|
135
|
-
4. Create git tag `vp-p{phase}-t{task}` **only after** steps 1–3 pass.
|
|
144
|
+
4. Create git tag `{projectPrefix}-vp-p{phase}-t{task}` **only after** steps 1–3 pass.
|
|
136
145
|
|
|
137
146
|
#### 3b. Execute Task
|
|
138
147
|
- Implement according to objective
|
|
@@ -177,7 +186,7 @@ When all tasks done:
|
|
|
177
186
|
- Run phase verification
|
|
178
187
|
- Check phase quality gate
|
|
179
188
|
- Write SUMMARY.md
|
|
180
|
-
- Create git tag: `vp-p{phase}-complete`
|
|
189
|
+
- Create git tag: `{projectPrefix}-vp-p{phase}-complete`
|
|
181
190
|
- Increment version if needed
|
|
182
191
|
|
|
183
192
|
### 6. Iterate
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
## Files Changed
|
|
28
28
|
|
|
29
|
-
> Populate by running: `git diff
|
|
29
|
+
> Populate by running: `TAG_PREFIX=$(vp-tools tag-prefix --raw) && git diff "${TAG_PREFIX}-p{{PHASE_NUMBER}}-t1"..HEAD --name-status | sort`
|
|
30
30
|
> List every file individually. Do NOT use glob patterns or summarize groups.
|
|
31
31
|
|
|
32
32
|
### Created
|
|
@@ -64,4 +64,4 @@
|
|
|
64
64
|
{{NOTES}}
|
|
65
65
|
|
|
66
66
|
---
|
|
67
|
-
Git Tag: `vp-p{{PHASE_NUMBER}}-complete`
|
|
67
|
+
Git Tag: `{projectPrefix}-vp-p{{PHASE_NUMBER}}-complete`
|
package/templates/phase/TASK.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
- **Status**: not_started | in_progress | blocked | done | skipped
|
|
6
6
|
- **Complexity**: {{COMPLEXITY}}
|
|
7
7
|
- **Dependencies**: {{DEPENDENCIES}}
|
|
8
|
-
- **Git Tag**: vp-p{{PHASE_NUMBER}}-t{{TASK_NUMBER}}
|
|
8
|
+
- **Git Tag**: {projectPrefix}-vp-p{{PHASE_NUMBER}}-t{{TASK_NUMBER}}
|
|
9
9
|
|
|
10
10
|
## Objective
|
|
11
11
|
|
|
@@ -97,5 +97,6 @@ manual:
|
|
|
97
97
|
## Rollback
|
|
98
98
|
```bash
|
|
99
99
|
# If need to undo this task:
|
|
100
|
-
|
|
100
|
+
TAG_PREFIX=$(vp-tools tag-prefix --raw)
|
|
101
|
+
git revert --no-commit $(git rev-list "${TAG_PREFIX}-p{{PHASE_NUMBER}}-t{{TASK_NUMBER}}".."${TAG_PREFIX}-p{{PHASE_NUMBER}}-t{{TASK_NUMBER}}-done")
|
|
101
102
|
```
|
package/workflows/audit.md
CHANGED
|
@@ -92,8 +92,8 @@ fi
|
|
|
92
92
|
### 1d. Git tags vs completed phases
|
|
93
93
|
```bash
|
|
94
94
|
# List completed phases (PHASE-STATE.md with status: complete)
|
|
95
|
-
# List git tags matching
|
|
96
|
-
COMPLETE_TAGS=$(git tag 2>/dev/null | grep -E '^vp-p[0-9]+-complete$' | sort)
|
|
95
|
+
# List git tags matching legacy + project-scoped complete format
|
|
96
|
+
COMPLETE_TAGS=$(git tag 2>/dev/null | grep -E '(^vp-p[0-9]+-complete$)|(^[a-z0-9-]+-vp-p[0-9]+-complete$)' | sort)
|
|
97
97
|
# Report any phase marked complete in PHASE-STATE.md without a git tag
|
|
98
98
|
```
|
|
99
99
|
|
|
@@ -206,8 +206,9 @@ for phase_state in $RECENT_PHASES; do
|
|
|
206
206
|
PHASE_DIR=$(dirname "$phase_state")
|
|
207
207
|
# Check if docs/ was updated in commits for this phase
|
|
208
208
|
PHASE_NUM=$(basename "$PHASE_DIR" | grep -o '^[0-9]*' | sed 's/^0*//')
|
|
209
|
-
|
|
210
|
-
|
|
209
|
+
TAG_PREFIX=$(vp-tools tag-prefix --raw 2>/dev/null || echo "vp")
|
|
210
|
+
PHASE_TAG="${TAG_PREFIX}-p${PHASE_NUM}-complete"
|
|
211
|
+
PREV_TAG=$(git tag --sort=-version:refname 2>/dev/null | grep -E "(vp-p.*-complete|[a-z0-9-]+-vp-p.*-complete)" | grep -A1 "^$PHASE_TAG$" | tail -1)
|
|
211
212
|
if [ -n "$PREV_TAG" ]; then
|
|
212
213
|
DOCS_CHANGED=$(git diff "$PREV_TAG"..HEAD --name-only 2>/dev/null | grep "^docs/" | wc -l | tr -d ' ')
|
|
213
214
|
if [ "$DOCS_CHANGED" -eq 0 ]; then
|
package/workflows/autonomous.md
CHANGED
|
@@ -119,7 +119,7 @@ Canonical order for every task: **Validate contract → Doc-first gate → Stack
|
|
|
119
119
|
|
|
120
120
|
If any check fails:
|
|
121
121
|
- Mark task `blocked` in `PHASE-STATE.md` and list what is missing under **Notes**
|
|
122
|
-
- **Do not** create `vp-p{phase}-t{task}`
|
|
122
|
+
- **Do not** create `{projectPrefix}-vp-p{phase}-t{task}`
|
|
123
123
|
- **Do not** proceed to **Execute Task**
|
|
124
124
|
|
|
125
125
|
#### Stack Preflight (token-efficient lookup)
|
|
@@ -137,7 +137,7 @@ If stack cache is missing:
|
|
|
137
137
|
|
|
138
138
|
Only after **Validate Task Contract**, **Pre-execution documentation gate**, and **Stack Preflight** (or explicit waiver logged in the task file with reason):
|
|
139
139
|
|
|
140
|
-
Create git tag: `vp-p{phase}-t{task}`
|
|
140
|
+
Create git tag: `{projectPrefix}-vp-p{phase}-t{task}`
|
|
141
141
|
Ensure `PHASE-STATE.md` already shows current task `in_progress` (set during the gate if not already).
|
|
142
142
|
|
|
143
143
|
#### Execute Task
|
|
@@ -175,10 +175,32 @@ quality_gate:
|
|
|
175
175
|
- no_lint_errors: true
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
+
#### Git Persistence Gate (BUG-003)
|
|
179
|
+
Before marking a task PASS, require durable git persistence:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Must have no unstaged/staged residue for this task
|
|
183
|
+
git status --porcelain
|
|
184
|
+
|
|
185
|
+
# Must track an upstream branch
|
|
186
|
+
git rev-parse --abbrev-ref --symbolic-full-name @{u}
|
|
187
|
+
|
|
188
|
+
# Must have no unpushed commits
|
|
189
|
+
git rev-list --count @{u}..HEAD
|
|
190
|
+
|
|
191
|
+
# Consolidated check helper (recommended)
|
|
192
|
+
node bin/vp-tools.cjs git-persistence --strict
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
If any check fails:
|
|
196
|
+
- **Do not** mark task `done`
|
|
197
|
+
- **Do not** advance phase progress/state files as PASS
|
|
198
|
+
- Route to control point (retry commit/push, rollback, or stop)
|
|
199
|
+
|
|
178
200
|
#### Handle Result
|
|
179
201
|
|
|
180
202
|
**PASS:**
|
|
181
|
-
- Create git tag: `vp-p{phase}-t{task}-done`
|
|
203
|
+
- Create git tag: `{projectPrefix}-vp-p{phase}-t{task}-done`
|
|
182
204
|
- Update PHASE-STATE.md immediately: task → done, append files changed by this task to Files Changed table (individual files, no glob patterns)
|
|
183
205
|
- Update TRACKER.md immediately
|
|
184
206
|
- Update HANDOFF.json immediately
|
|
@@ -224,7 +246,8 @@ When all tasks in phase are done/skipped:
|
|
|
224
246
|
Populate `{{CREATED_FILES}}`, `{{MODIFIED_FILES}}`, `{{DELETED_FILES}}` from git:
|
|
225
247
|
```bash
|
|
226
248
|
# Get ALL individual files changed since phase start tag
|
|
227
|
-
|
|
249
|
+
TAG_PREFIX=$(node bin/vp-tools.cjs tag-prefix --raw)
|
|
250
|
+
git diff "${TAG_PREFIX}-p{phase}-t1"..HEAD --name-status | sort
|
|
228
251
|
```
|
|
229
252
|
List **every file individually** — do NOT use glob patterns or summarize.
|
|
230
253
|
Correct example:
|
|
@@ -243,7 +266,7 @@ When all tasks in phase are done/skipped:
|
|
|
243
266
|
| smarttrack-*/pom.xml (8 files) | 1.1 | ← WRONG: glob pattern
|
|
244
267
|
| smarttrack-*/src/** (7 files) | 1.1 | ← WRONG: summarized
|
|
245
268
|
```
|
|
246
|
-
4. Create git tag: `vp-p{phase}-complete`
|
|
269
|
+
4. Create git tag: `{projectPrefix}-vp-p{phase}-complete`
|
|
247
270
|
5. Check version bump needed:
|
|
248
271
|
- Features added → MINOR
|
|
249
272
|
- Fixes only → PATCH
|
|
@@ -252,6 +275,7 @@ When all tasks in phase are done/skipped:
|
|
|
252
275
|
```bash
|
|
253
276
|
git push
|
|
254
277
|
git push --tags
|
|
278
|
+
node bin/vp-tools.cjs git-persistence --strict
|
|
255
279
|
```
|
|
256
280
|
|
|
257
281
|
### 5a. Sync ROADMAP.md (after every phase complete)
|
|
@@ -280,7 +304,8 @@ Commit: `chore: update ROADMAP.md — phase {N} complete`
|
|
|
280
304
|
if [ ! -d "skills" ]; then
|
|
281
305
|
echo "→ Skipping skills-reference update (not a viepilot framework repo)"
|
|
282
306
|
else
|
|
283
|
-
|
|
307
|
+
TAG_PREFIX=$(node bin/vp-tools.cjs tag-prefix --raw)
|
|
308
|
+
NEW_SKILLS=$(git diff "${TAG_PREFIX}-p{phase}-t1"..HEAD --name-only | grep 'skills/.*/SKILL\.md' | sed 's|skills/||; s|/SKILL\.md||')
|
|
284
309
|
if [ -n "$NEW_SKILLS" ]; then
|
|
285
310
|
# Append new sections to docs/skills-reference.md
|
|
286
311
|
# (same incremental logic as workflows/documentation.md step 3B)
|
|
@@ -392,7 +417,8 @@ Options:
|
|
|
392
417
|
|
|
393
418
|
**Rollback:**
|
|
394
419
|
```bash
|
|
395
|
-
|
|
420
|
+
TAG_PREFIX=$(node bin/vp-tools.cjs tag-prefix --raw)
|
|
421
|
+
git revert --no-commit $(git rev-list "${TAG_PREFIX}-p{phase}-t{task}"..HEAD)
|
|
396
422
|
```
|
|
397
423
|
- Reset task → not_started
|
|
398
424
|
- Continue or stop
|
package/workflows/rollback.md
CHANGED
|
@@ -8,7 +8,7 @@ Safe rollback to any ViePilot checkpoint với backup và state preservation.
|
|
|
8
8
|
## 1. List Available Checkpoints
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
git tag
|
|
11
|
+
git tag --sort=-creatordate | rg "(^vp-p|^-*vp-backup|^[a-z0-9-]+-vp-p|^[a-z0-9-]+-vp-backup)" | head -20
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
For each tag, get info:
|
|
@@ -41,7 +41,7 @@ If `--list` flag, stop here.
|
|
|
41
41
|
Validate tag exists.
|
|
42
42
|
|
|
43
43
|
**If --latest:**
|
|
44
|
-
Select most recent
|
|
44
|
+
Select most recent checkpoint tag (project-scoped or legacy).
|
|
45
45
|
|
|
46
46
|
**Otherwise:**
|
|
47
47
|
Ask user to select from list or enter tag name.
|
|
@@ -98,7 +98,8 @@ Wait for confirmation.
|
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
100
|
# Create backup tag
|
|
101
|
-
|
|
101
|
+
TAG_PREFIX="$(vp-tools tag-prefix --raw)"
|
|
102
|
+
BACKUP_TAG="${TAG_PREFIX}-backup-$(date +%Y%m%d-%H%M%S)"
|
|
102
103
|
git tag $BACKUP_TAG
|
|
103
104
|
|
|
104
105
|
# Backup state files
|
|
@@ -126,10 +127,10 @@ git log -1 --oneline
|
|
|
126
127
|
<step name="update_state">
|
|
127
128
|
## 7. Update State Files
|
|
128
129
|
|
|
129
|
-
Parse tag to determine phase/task:
|
|
130
|
-
- `vp-p{N}-t{M}` → Phase N, Task M, status: in_progress
|
|
131
|
-
- `vp-p{N}-t{M}-done` → Phase N, Task M+1, status: not_started
|
|
132
|
-
- `vp-p{N}-complete` → Phase N+1, Task 1, status: not_started
|
|
130
|
+
Parse tag to determine phase/task (support both legacy and project-scoped):
|
|
131
|
+
- `vp-p{N}-t{M}` or `{project}-vp-p{N}-t{M}` → Phase N, Task M, status: in_progress
|
|
132
|
+
- `vp-p{N}-t{M}-done` or `{project}-vp-p{N}-t{M}-done` → Phase N, Task M+1, status: not_started
|
|
133
|
+
- `vp-p{N}-complete` or `{project}-vp-p{N}-complete` → Phase N+1, Task 1, status: not_started
|
|
133
134
|
|
|
134
135
|
Update HANDOFF.json accordingly.
|
|
135
136
|
Update TRACKER.md progress.
|