viepilot 1.1.0 → 1.2.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
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
16
 
17
17
  ### Fixed
18
18
 
19
+ - **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
20
  - **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
21
 
21
22
  ### Documentation
package/README.md CHANGED
@@ -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
 
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 -l "vp-*" --sort=-creatordate', {
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,22 @@ 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
+
619
637
  /**
620
638
  * Check for potential conflicts
621
639
  */
@@ -803,6 +821,14 @@ const commands = {
803
821
  'vp-tools version bump minor',
804
822
  ],
805
823
  },
824
+ 'tag-prefix': {
825
+ usage: 'vp-tools tag-prefix [--raw]',
826
+ description: 'Return deterministic project-scoped checkpoint tag prefix',
827
+ examples: [
828
+ 'vp-tools tag-prefix',
829
+ 'vp-tools tag-prefix --raw',
830
+ ],
831
+ },
806
832
  };
807
833
 
808
834
  if (command && commandHelp[command]) {
@@ -839,6 +865,7 @@ ${colors.cyan}Commands:${colors.reset}
839
865
  ${colors.bold}reset${colors.reset} <target> [-f] Reset task/phase/all state (interactive)
840
866
  ${colors.bold}clean${colors.reset} [-f] [--dry-run] Clean generated files (interactive)
841
867
  ${colors.bold}checkpoints${colors.reset} List all ViePilot checkpoints (git tags)
868
+ ${colors.bold}tag-prefix${colors.reset} [--raw] Show project-scoped checkpoint prefix
842
869
  ${colors.bold}conflicts${colors.reset} Check for potential conflicts
843
870
  ${colors.bold}save-state${colors.reset} Save current state for precise resume
844
871
  ${colors.bold}help${colors.reset} [command] Show help (optionally for specific command)
@@ -109,9 +109,10 @@ AI pauses for user input when:
109
109
  - Blocker encountered
110
110
 
111
111
  ### 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
112
+ - `{project}-vp-p{phase}-t{task}` - Task started
113
+ - `{project}-vp-p{phase}-t{task}-done` - Task completed
114
+ - `{project}-vp-p{phase}-complete` - Phase completed
115
+ - Legacy `vp-p...` tags are still accepted for compatibility
115
116
 
116
117
  ---
117
118
 
@@ -337,9 +338,9 @@ CHANGELOG.md (updated)
337
338
  ### Checkpoint Types
338
339
  | Tag Pattern | Created By | Meaning |
339
340
  |-------------|------------|---------|
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 |
341
+ | `{project}-vp-p{N}-t{M}` | vp-auto | Task started |
342
+ | `{project}-vp-p{N}-t{M}-done` | vp-auto | Task completed |
343
+ | `{project}-vp-p{N}-complete` | vp-auto | Phase completed |
343
344
  | `v{semver}` | vp-auto | Version release |
344
345
 
345
346
  ### Safety Guarantees
@@ -13,11 +13,11 @@ 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
21
 
22
22
  ## Flags
23
23
 
@@ -87,15 +87,17 @@ Nếu bất kỳ gate nào fail → control point.
87
87
  Mỗi task tạo 2 git tags:
88
88
 
89
89
  ```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
90
+ viepilot-vp-p2-t3 # Bắt đầu task 3 của phase 2
91
+ viepilot-vp-p2-t3-done # Hoàn thành task 3 của phase 2
92
92
  ```
93
93
 
94
94
  Khi phase complete:
95
95
  ```bash
96
- vp-p2-complete # Phase 2 hoàn thành
96
+ viepilot-vp-p2-complete # Phase 2 hoàn thành
97
97
  ```
98
98
 
99
+ Legacy tags `vp-p...` vẫn được hỗ trợ khi list/rollback để tương thích dự án cũ.
100
+
99
101
  Xem tất cả checkpoints:
100
102
  ```bash
101
103
  vp-tools checkpoints
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viepilot",
3
- "version": "1.1.0",
3
+ "version": "1.2.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": {
@@ -47,7 +47,7 @@ If required task details are missing, do not implement until task contract is re
47
47
  **Doc-first gate before implementation (BUG-001):**
48
48
  - 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
49
  - `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).
50
+ - **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
51
 
52
52
  **Preflight before each task implementation:**
53
53
  - Read `.viepilot/STACKS.md` (if exists)
@@ -132,7 +132,7 @@ Stack preflight:
132
132
  1. Validate task contract (`workflows/autonomous.md`).
133
133
  2. Record plan in task file; set task `in_progress` in `PHASE-STATE.md`.
134
134
  3. Stack preflight.
135
- 4. Create git tag `vp-p{phase}-t{task}` **only after** steps 1–3 pass.
135
+ 4. Create git tag `{projectPrefix}-vp-p{phase}-t{task}` **only after** steps 1–3 pass.
136
136
 
137
137
  #### 3b. Execute Task
138
138
  - Implement according to objective
@@ -177,7 +177,7 @@ When all tasks done:
177
177
  - Run phase verification
178
178
  - Check phase quality gate
179
179
  - Write SUMMARY.md
180
- - Create git tag: `vp-p{phase}-complete`
180
+ - Create git tag: `{projectPrefix}-vp-p{phase}-complete`
181
181
  - Increment version if needed
182
182
 
183
183
  ### 6. Iterate
@@ -26,7 +26,7 @@
26
26
 
27
27
  ## Files Changed
28
28
 
29
- > Populate by running: `git diff vp-p{{PHASE_NUMBER}}-t1..HEAD --name-status | sort`
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`
@@ -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
- git revert --no-commit $(git rev-list vp-p{{PHASE_NUMBER}}-t{{TASK_NUMBER}}..vp-p{{PHASE_NUMBER}}-t{{TASK_NUMBER}}-done)
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
  ```
@@ -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 vp-p{N}-complete
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
- PHASE_TAG="vp-p${PHASE_NUM}-complete"
210
- PREV_TAG=$(git tag --sort=-version:refname 2>/dev/null | grep "vp-p.*-complete" | grep -A1 "^$PHASE_TAG$" | tail -1)
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
@@ -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
@@ -178,7 +178,7 @@ quality_gate:
178
178
  #### Handle Result
179
179
 
180
180
  **PASS:**
181
- - Create git tag: `vp-p{phase}-t{task}-done`
181
+ - Create git tag: `{projectPrefix}-vp-p{phase}-t{task}-done`
182
182
  - Update PHASE-STATE.md immediately: task → done, append files changed by this task to Files Changed table (individual files, no glob patterns)
183
183
  - Update TRACKER.md immediately
184
184
  - Update HANDOFF.json immediately
@@ -224,7 +224,8 @@ When all tasks in phase are done/skipped:
224
224
  Populate `{{CREATED_FILES}}`, `{{MODIFIED_FILES}}`, `{{DELETED_FILES}}` from git:
225
225
  ```bash
226
226
  # Get ALL individual files changed since phase start tag
227
- git diff vp-p{phase}-t1..HEAD --name-status | sort
227
+ TAG_PREFIX=$(node bin/vp-tools.cjs tag-prefix --raw)
228
+ git diff "${TAG_PREFIX}-p{phase}-t1"..HEAD --name-status | sort
228
229
  ```
229
230
  List **every file individually** — do NOT use glob patterns or summarize.
230
231
  Correct example:
@@ -243,7 +244,7 @@ When all tasks in phase are done/skipped:
243
244
  | smarttrack-*/pom.xml (8 files) | 1.1 | ← WRONG: glob pattern
244
245
  | smarttrack-*/src/** (7 files) | 1.1 | ← WRONG: summarized
245
246
  ```
246
- 4. Create git tag: `vp-p{phase}-complete`
247
+ 4. Create git tag: `{projectPrefix}-vp-p{phase}-complete`
247
248
  5. Check version bump needed:
248
249
  - Features added → MINOR
249
250
  - Fixes only → PATCH
@@ -280,7 +281,8 @@ Commit: `chore: update ROADMAP.md — phase {N} complete`
280
281
  if [ ! -d "skills" ]; then
281
282
  echo "→ Skipping skills-reference update (not a viepilot framework repo)"
282
283
  else
283
- NEW_SKILLS=$(git diff vp-p{phase}-t1..HEAD --name-only | grep 'skills/.*/SKILL\.md' | sed 's|skills/||; s|/SKILL\.md||')
284
+ TAG_PREFIX=$(node bin/vp-tools.cjs tag-prefix --raw)
285
+ NEW_SKILLS=$(git diff "${TAG_PREFIX}-p{phase}-t1"..HEAD --name-only | grep 'skills/.*/SKILL\.md' | sed 's|skills/||; s|/SKILL\.md||')
284
286
  if [ -n "$NEW_SKILLS" ]; then
285
287
  # Append new sections to docs/skills-reference.md
286
288
  # (same incremental logic as workflows/documentation.md step 3B)
@@ -392,7 +394,8 @@ Options:
392
394
 
393
395
  **Rollback:**
394
396
  ```bash
395
- git revert --no-commit $(git rev-list vp-p{phase}-t{task}..HEAD)
397
+ TAG_PREFIX=$(node bin/vp-tools.cjs tag-prefix --raw)
398
+ git revert --no-commit $(git rev-list "${TAG_PREFIX}-p{phase}-t{task}"..HEAD)
396
399
  ```
397
400
  - Reset task → not_started
398
401
  - Continue or stop
@@ -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 -l "vp-*" --sort=-creatordate | head -20
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 vp-* tag.
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
- BACKUP_TAG="vp-backup-$(date +%Y%m%d-%H%M%S)"
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.