viepilot 1.9.7 → 1.9.9

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
@@ -19,6 +19,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
19
 
20
20
  - None yet.
21
21
 
22
+ ## [1.9.9] - 2026-04-02
23
+
24
+ ### Fixed
25
+
26
+ - **ENH-025**: Thêm explicit READ-ONLY guard cho `.viepilot/ui-direction/` vào 3 workflows: `autonomous.md` (⛔ guard trong ENH-024 block), `crystallize.md` (Source of truth policy trong `consume_ui_direction` step), `request.md` (ui-direction guard redirect trong `brainstorm_continuation`). Design principle được enforce: ui-direction = frozen design contract — chỉ `vp-brainstorm` có quyền write; thay đổi ui-direction phải mở phiên brainstorm mới (session-id mới).
27
+
28
+ ## [1.9.8] - 2026-04-02
29
+
30
+ ### Fixed
31
+
32
+ - **BUG-005**: `claude-code` install target không mirror `workflows/`, `bin/`, `templates/` sang `~/.claude/viepilot/` dẫn đến tất cả skills bị broken trên máy không có Cursor. Fix: `buildInstallPlan` nay tạo `claudeViepilotDir = ~/.claude/viepilot/`, mirror toàn bộ artifacts, và thêm bước `rewrite_paths_in_dir` để replace `.cursor/viepilot` → `.claude/viepilot` trong SKILL.md files. Cursor targets không bị ảnh hưởng. (+6 tests, 314 total pass)
33
+
22
34
  ## [1.9.7] - 2026-04-02
23
35
 
24
36
  ### Fixed
@@ -94,6 +94,7 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
94
94
  const installTargets = Array.isArray(opts.installTargets) ? opts.installTargets : [];
95
95
  const installClaudeSkills = installTargets.includes('claude-code');
96
96
  const claudeSkillsDir = installClaudeSkills ? path.join(home, '.claude', 'skills') : null;
97
+ const claudeViepilotDir = installClaudeSkills ? path.join(home, '.claude', 'viepilot') : null;
97
98
 
98
99
  let wantPathShim = opts.wantPathShim;
99
100
  if (wantPathShim === undefined) {
@@ -152,6 +153,55 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
152
153
  steps.push({ kind: 'copy_dir', from: src, to: dest });
153
154
  }
154
155
  }
156
+
157
+ // BUG-005: mirror workflows/templates/bin/lib to ~/.claude/viepilot/
158
+ if (claudeViepilotDir) {
159
+ for (const sub of [
160
+ 'workflows',
161
+ path.join('templates', 'project'),
162
+ path.join('templates', 'phase'),
163
+ 'bin',
164
+ 'lib',
165
+ ]) {
166
+ steps.push({ kind: 'mkdir', path: path.join(claudeViepilotDir, sub) });
167
+ }
168
+
169
+ for (const ent of listDirEntries(root, 'workflows')) {
170
+ const src = path.join(root, 'workflows', ent.name);
171
+ const dest = path.join(claudeViepilotDir, 'workflows', ent.name);
172
+ steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
173
+ }
174
+
175
+ for (const ent of listDirEntries(root, path.join('templates', 'project'))) {
176
+ const src = path.join(root, 'templates', 'project', ent.name);
177
+ const dest = path.join(claudeViepilotDir, 'templates', 'project', ent.name);
178
+ steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
179
+ }
180
+
181
+ for (const ent of listDirEntries(root, path.join('templates', 'phase'))) {
182
+ const src = path.join(root, 'templates', 'phase', ent.name);
183
+ const dest = path.join(claudeViepilotDir, 'templates', 'phase', ent.name);
184
+ steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
185
+ }
186
+
187
+ for (const f of ['vp-tools.cjs', 'viepilot.cjs']) {
188
+ steps.push({ kind: 'copy_file', from: path.join(root, 'bin', f), to: path.join(claudeViepilotDir, 'bin', f) });
189
+ }
190
+ steps.push({
191
+ kind: 'copy_file',
192
+ from: path.join(root, 'lib', 'cli-shared.cjs'),
193
+ to: path.join(claudeViepilotDir, 'lib', 'cli-shared.cjs'),
194
+ });
195
+
196
+ // Rewrite execution_context paths in mirrored skill files
197
+ steps.push({
198
+ kind: 'rewrite_paths_in_dir',
199
+ dir: claudeSkillsDir,
200
+ glob: '**/*.md',
201
+ from: '.cursor/viepilot',
202
+ to: '.claude/viepilot',
203
+ });
204
+ }
155
205
  }
156
206
 
157
207
  for (const ent of listDirEntries(root, 'workflows')) {
@@ -245,6 +295,7 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
245
295
  paths: {
246
296
  cursorSkillsDir,
247
297
  claudeSkillsDir,
298
+ claudeViepilotDir,
248
299
  viepilotDir,
249
300
  viepilotUserDataDir,
250
301
  viepilotProfilesDir,
@@ -268,6 +319,9 @@ function formatPlanLines(plan) {
268
319
  if (plan.paths.claudeSkillsDir) {
269
320
  lines.push(` skills (Claude Code): ${plan.paths.claudeSkillsDir}`);
270
321
  }
322
+ if (plan.paths.claudeViepilotDir) {
323
+ lines.push(` viepilot (Claude Code): ${plan.paths.claudeViepilotDir}`);
324
+ }
271
325
  lines.push(` viepilot: ${plan.paths.viepilotDir}`);
272
326
  if (plan.paths.viepilotUserDataDir) {
273
327
  lines.push(` userData (~/.viepilot): ${plan.paths.viepilotUserDataDir}`);
@@ -302,6 +356,9 @@ function formatPlanLines(plan) {
302
356
  lines.push(`${n}. path shim: ${s.links.map((l) => `${l.path} -> ${l.target}`).join('; ')}`);
303
357
  if (s.note) lines.push(` (${s.note})`);
304
358
  break;
359
+ case 'rewrite_paths_in_dir':
360
+ lines.push(`${n}. rewrite_paths_in_dir ${s.dir}: "${s.from}" → "${s.to}" in ${s.glob}`);
361
+ break;
305
362
  default:
306
363
  lines.push(`${n}. ${JSON.stringify(s)}`);
307
364
  }
@@ -465,6 +522,29 @@ function applyInstallPlan(plan, options = {}) {
465
522
  }
466
523
  }
467
524
  break;
525
+ case 'rewrite_paths_in_dir': {
526
+ if (dryRun) {
527
+ logs.push(`[dry-run] rewrite_paths_in_dir ${step.dir}: "${step.from}" → "${step.to}" in ${step.glob}`);
528
+ break;
529
+ }
530
+ const rewriteDir = (dir) => {
531
+ if (!fs.existsSync(dir)) return;
532
+ for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
533
+ const fullPath = path.join(dir, ent.name);
534
+ if (ent.isDirectory()) {
535
+ rewriteDir(fullPath);
536
+ } else if (ent.isFile() && ent.name.endsWith('.md')) {
537
+ const content = fs.readFileSync(fullPath, 'utf8');
538
+ if (content.includes(step.from)) {
539
+ fs.writeFileSync(fullPath, content.split(step.from).join(step.to), 'utf8');
540
+ logs.push(`rewrite: ${fullPath}`);
541
+ }
542
+ }
543
+ }
544
+ };
545
+ rewriteDir(step.dir);
546
+ break;
547
+ }
468
548
  default:
469
549
  logs.push(`unknown step kind: ${JSON.stringify(step)}`);
470
550
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viepilot",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
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": {