viepilot 1.14.0 → 2.4.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 +191 -0
- package/README.md +27 -17
- package/bin/viepilot.cjs +19 -9
- package/bin/vp-tools.cjs +193 -0
- package/docs/user/features/adapters.md +74 -0
- package/docs/user/features/hooks.md +93 -0
- package/lib/adapters/antigravity.cjs +33 -0
- package/lib/adapters/claude-code.cjs +42 -0
- package/lib/adapters/codex.cjs +34 -0
- package/lib/adapters/cursor.cjs +32 -0
- package/lib/adapters/index.cjs +28 -0
- package/lib/hooks/brainstorm-staleness.cjs +231 -0
- package/lib/viepilot-config.cjs +103 -0
- package/lib/viepilot-install.cjs +125 -152
- package/package.json +1 -3
- package/skills/vp-audit/SKILL.md +23 -23
- package/skills/vp-auto/SKILL.md +23 -9
- package/skills/vp-brainstorm/SKILL.md +44 -38
- package/skills/vp-crystallize/SKILL.md +25 -19
- package/skills/vp-debug/SKILL.md +4 -4
- package/skills/vp-docs/SKILL.md +8 -8
- package/skills/vp-evolve/SKILL.md +26 -13
- package/skills/vp-info/SKILL.md +24 -24
- package/skills/vp-pause/SKILL.md +7 -7
- package/skills/vp-request/SKILL.md +14 -14
- package/skills/vp-resume/SKILL.md +6 -6
- package/skills/vp-rollback/SKILL.md +4 -4
- package/skills/vp-status/SKILL.md +4 -4
- package/skills/vp-task/SKILL.md +2 -2
- package/skills/vp-ui-components/SKILL.md +14 -14
- package/skills/vp-update/SKILL.md +18 -18
- package/templates/architect/apis.html +11 -10
- package/templates/architect/architect-actions.js +217 -0
- package/templates/architect/architecture.html +8 -7
- package/templates/architect/data-flow.html +5 -4
- package/templates/architect/decisions.html +4 -3
- package/templates/architect/deployment.html +10 -9
- package/templates/architect/erd.html +7 -6
- package/templates/architect/feature-map.html +5 -4
- package/templates/architect/sequence-diagram.html +6 -5
- package/templates/architect/style.css +146 -0
- package/templates/architect/tech-notes.html +3 -2
- package/templates/architect/tech-stack.html +8 -7
- package/templates/architect/user-use-cases.html +8 -7
- package/templates/project/AI-GUIDE.md +49 -49
- package/workflows/audit.md +3 -3
- package/workflows/autonomous.md +70 -5
- package/workflows/brainstorm.md +398 -222
- package/workflows/crystallize.md +51 -33
- package/workflows/debug.md +9 -9
- package/workflows/documentation.md +5 -5
- package/workflows/evolve.md +46 -12
- package/workflows/pause-work.md +2 -2
- package/workflows/request.md +8 -8
- package/workflows/resume-work.md +1 -1
- package/workflows/rollback.md +1 -1
- package/dev-install.sh +0 -150
- package/install.sh +0 -125
package/lib/viepilot-install.cjs
CHANGED
|
@@ -7,6 +7,8 @@ const fs = require('fs');
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const os = require('os');
|
|
9
9
|
const { resolveViepilotPackageRoot } = require('./viepilot-info.cjs');
|
|
10
|
+
const { writeConfig } = require('./viepilot-config.cjs');
|
|
11
|
+
const { getAdapter } = require('./adapters/index.cjs');
|
|
10
12
|
|
|
11
13
|
/** @see docs/dev/global-profiles.md (FEAT-009) */
|
|
12
14
|
const VIEPILOT_PROFILE_MAP_SEED = `# ViePilot profile map
|
|
@@ -24,7 +26,7 @@ Machine-level registry for reusable org/client profiles. Add rows when you creat
|
|
|
24
26
|
function normalizeInstallEnv(envSource = process.env) {
|
|
25
27
|
return {
|
|
26
28
|
autoYes: envSource.VIEPILOT_AUTO_YES === '1',
|
|
27
|
-
profile: envSource.VIEPILOT_INSTALL_PROFILE || '
|
|
29
|
+
profile: envSource.VIEPILOT_INSTALL_PROFILE || 'claude-code',
|
|
28
30
|
addPath: envSource.VIEPILOT_ADD_PATH === '1',
|
|
29
31
|
symlinkSkills: envSource.VIEPILOT_SYMLINK_SKILLS === '1',
|
|
30
32
|
};
|
|
@@ -85,16 +87,34 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
|
|
|
85
87
|
const env = normalizeInstallEnv(envSource);
|
|
86
88
|
const home =
|
|
87
89
|
opts.overrideHomedir != null ? path.resolve(opts.overrideHomedir) : os.homedir();
|
|
88
|
-
const cursorSkillsDir = path.join(home, '.cursor', 'skills');
|
|
89
|
-
const viepilotDir = path.join(home, '.cursor', 'viepilot');
|
|
90
90
|
const viepilotUserDataDir = path.join(home, '.viepilot');
|
|
91
91
|
const viepilotProfilesDir = path.join(viepilotUserDataDir, 'profiles');
|
|
92
92
|
const viepilotProfileMapPath = path.join(viepilotUserDataDir, 'profile-map.md');
|
|
93
93
|
|
|
94
94
|
const installTargets = Array.isArray(opts.installTargets) ? opts.installTargets : [];
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
|
|
96
|
+
// Resolve target IDs to adapters.
|
|
97
|
+
// Backward compat: if no installTargets, infer from env.profile (cursor-agent/cursor-ide → cursor).
|
|
98
|
+
// Default: claude-code (FEAT-013 — Claude Code is primary platform).
|
|
99
|
+
let targetIds;
|
|
100
|
+
if (installTargets.length > 0) {
|
|
101
|
+
targetIds = installTargets;
|
|
102
|
+
} else if (env.profile === 'cursor-agent' || env.profile === 'cursor-ide') {
|
|
103
|
+
targetIds = [env.profile];
|
|
104
|
+
} else {
|
|
105
|
+
targetIds = ['claude-code'];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Deduplicate by adapter canonical id (cursor-agent + cursor-ide → one cursor install).
|
|
109
|
+
const seenAdapterIds = new Set();
|
|
110
|
+
const selectedAdapters = [];
|
|
111
|
+
for (const id of targetIds) {
|
|
112
|
+
const adapter = getAdapter(id);
|
|
113
|
+
if (!seenAdapterIds.has(adapter.id)) {
|
|
114
|
+
seenAdapterIds.add(adapter.id);
|
|
115
|
+
selectedAdapters.push(adapter);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
98
118
|
|
|
99
119
|
let wantPathShim = opts.wantPathShim;
|
|
100
120
|
if (wantPathShim === undefined) {
|
|
@@ -104,19 +124,6 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
|
|
|
104
124
|
/** @type {object[]} */
|
|
105
125
|
const steps = [];
|
|
106
126
|
|
|
107
|
-
const mkdirTargets = [
|
|
108
|
-
cursorSkillsDir,
|
|
109
|
-
path.join(viepilotDir, 'workflows'),
|
|
110
|
-
path.join(viepilotDir, 'templates', 'project'),
|
|
111
|
-
path.join(viepilotDir, 'templates', 'phase'),
|
|
112
|
-
path.join(viepilotDir, 'bin'),
|
|
113
|
-
path.join(viepilotDir, 'lib'),
|
|
114
|
-
path.join(viepilotDir, 'ui-components'),
|
|
115
|
-
];
|
|
116
|
-
for (const dir of mkdirTargets) {
|
|
117
|
-
steps.push({ kind: 'mkdir', path: dir });
|
|
118
|
-
}
|
|
119
|
-
|
|
120
127
|
steps.push({ kind: 'mkdir', path: viepilotProfilesDir });
|
|
121
128
|
steps.push({
|
|
122
129
|
kind: 'write_file_if_missing',
|
|
@@ -124,147 +131,81 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
|
|
|
124
131
|
content: VIEPILOT_PROFILE_MAP_SEED,
|
|
125
132
|
});
|
|
126
133
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
const binFiles = ['vp-tools.cjs', 'viepilot.cjs'];
|
|
135
|
+
const libFiles = ['cli-shared.cjs', 'viepilot-info.cjs', 'viepilot-update.cjs', 'viepilot-install.cjs', 'viepilot-config.cjs'];
|
|
136
|
+
const uiRoot = path.join(root, 'ui-components');
|
|
137
|
+
|
|
138
|
+
// One install loop per selected adapter (replaces cursor block + claude-code if-block).
|
|
139
|
+
for (const adapter of selectedAdapters) {
|
|
140
|
+
const skillsDir = adapter.skillsDir(home);
|
|
141
|
+
const vpDir = adapter.viepilotDir(home);
|
|
142
|
+
|
|
143
|
+
// mkdir: skills dir + all viepilot subdirs
|
|
144
|
+
steps.push({ kind: 'mkdir', path: skillsDir });
|
|
145
|
+
for (const sub of adapter.installSubdirs) {
|
|
146
|
+
steps.push({ kind: 'mkdir', path: path.join(vpDir, sub) });
|
|
138
147
|
}
|
|
139
|
-
}
|
|
140
148
|
|
|
141
|
-
|
|
142
|
-
steps.push({ kind: 'mkdir', path: claudeSkillsDir });
|
|
149
|
+
// copy skills into skillsDir
|
|
143
150
|
for (const name of listSkillDirNames(root)) {
|
|
144
151
|
const src = path.join(root, 'skills', name);
|
|
145
|
-
const dest = path.join(
|
|
152
|
+
const dest = path.join(skillsDir, name);
|
|
146
153
|
if (env.symlinkSkills) {
|
|
147
|
-
steps.push({
|
|
148
|
-
kind: 'symlink_dir',
|
|
149
|
-
target: dest,
|
|
150
|
-
sourceAbsolute: path.resolve(src),
|
|
151
|
-
});
|
|
154
|
+
steps.push({ kind: 'symlink_dir', target: dest, sourceAbsolute: path.resolve(src) });
|
|
152
155
|
} else {
|
|
153
156
|
steps.push({ kind: 'copy_dir', from: src, to: dest });
|
|
154
157
|
}
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
for (const f of ['cli-shared.cjs', 'viepilot-info.cjs', 'viepilot-update.cjs', 'viepilot-install.cjs']) {
|
|
191
|
-
steps.push({ kind: 'copy_file', from: path.join(root, 'lib', f), to: path.join(claudeViepilotDir, 'lib', f) });
|
|
192
|
-
}
|
|
193
|
-
// BUG-007: copy package.json so resolveViepilotPackageRoot() finds the root
|
|
194
|
-
// when vp-tools runs from ~/.claude/viepilot/ (CWD ≠ viepilot source repo)
|
|
195
|
-
steps.push({ kind: 'copy_file', from: path.join(root, 'package.json'), to: path.join(claudeViepilotDir, 'package.json') });
|
|
196
|
-
|
|
197
|
-
// Rewrite execution_context paths in mirrored skill files
|
|
198
|
-
steps.push({
|
|
199
|
-
kind: 'rewrite_paths_in_dir',
|
|
200
|
-
dir: claudeSkillsDir,
|
|
201
|
-
glob: '**/*.md',
|
|
202
|
-
from: '.cursor/viepilot',
|
|
203
|
-
to: '.claude/viepilot',
|
|
204
|
-
});
|
|
160
|
+
// copy viepilot files into vpDir
|
|
161
|
+
for (const ent of listDirEntries(root, 'workflows')) {
|
|
162
|
+
const src = path.join(root, 'workflows', ent.name);
|
|
163
|
+
const dest = path.join(vpDir, 'workflows', ent.name);
|
|
164
|
+
steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
|
|
205
165
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const dest = path.join(viepilotDir, 'workflows', ent.name);
|
|
211
|
-
if (ent.isDirectory()) {
|
|
212
|
-
steps.push({ kind: 'copy_dir', from: src, to: dest });
|
|
213
|
-
} else if (ent.isFile()) {
|
|
214
|
-
steps.push({ kind: 'copy_file', from: src, to: dest });
|
|
166
|
+
for (const ent of listDirEntries(root, path.join('templates', 'project'))) {
|
|
167
|
+
const src = path.join(root, 'templates', 'project', ent.name);
|
|
168
|
+
const dest = path.join(vpDir, 'templates', 'project', ent.name);
|
|
169
|
+
steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
|
|
215
170
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const dest = path.join(viepilotDir, 'templates', 'project', ent.name);
|
|
221
|
-
if (ent.isDirectory()) {
|
|
222
|
-
steps.push({ kind: 'copy_dir', from: src, to: dest });
|
|
223
|
-
} else if (ent.isFile()) {
|
|
224
|
-
steps.push({ kind: 'copy_file', from: src, to: dest });
|
|
171
|
+
for (const ent of listDirEntries(root, path.join('templates', 'phase'))) {
|
|
172
|
+
const src = path.join(root, 'templates', 'phase', ent.name);
|
|
173
|
+
const dest = path.join(vpDir, 'templates', 'phase', ent.name);
|
|
174
|
+
steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
|
|
225
175
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const dest = path.join(viepilotDir, 'templates', 'phase', ent.name);
|
|
231
|
-
if (ent.isDirectory()) {
|
|
232
|
-
steps.push({ kind: 'copy_dir', from: src, to: dest });
|
|
233
|
-
} else if (ent.isFile()) {
|
|
234
|
-
steps.push({ kind: 'copy_file', from: src, to: dest });
|
|
176
|
+
for (const ent of listDirEntries(root, path.join('templates', 'architect'))) {
|
|
177
|
+
const src = path.join(root, 'templates', 'architect', ent.name);
|
|
178
|
+
const dest = path.join(vpDir, 'templates', 'architect', ent.name);
|
|
179
|
+
steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
|
|
235
180
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
steps.push({ kind: 'copy_file', from: src, to: dest });
|
|
181
|
+
for (const f of binFiles) {
|
|
182
|
+
steps.push({ kind: 'copy_file', from: path.join(root, 'bin', f), to: path.join(vpDir, 'bin', f) });
|
|
183
|
+
}
|
|
184
|
+
for (const f of libFiles) {
|
|
185
|
+
steps.push({ kind: 'copy_file', from: path.join(root, 'lib', f), to: path.join(vpDir, 'lib', f) });
|
|
186
|
+
}
|
|
187
|
+
if (fs.existsSync(uiRoot)) {
|
|
188
|
+
for (const ent of listDirEntries(root, 'ui-components')) {
|
|
189
|
+
const src = path.join(root, 'ui-components', ent.name);
|
|
190
|
+
const dest = path.join(vpDir, 'ui-components', ent.name);
|
|
191
|
+
steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
|
|
247
192
|
}
|
|
248
193
|
}
|
|
249
|
-
|
|
194
|
+
// BUG-007: copy package.json so resolveViepilotPackageRoot() finds the root
|
|
195
|
+
steps.push({ kind: 'copy_file', from: path.join(root, 'package.json'), to: path.join(vpDir, 'package.json') });
|
|
250
196
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
from: path.join(root, 'bin', f),
|
|
256
|
-
to: path.join(viepilotDir, 'bin', f),
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
for (const f of ['cli-shared.cjs', 'viepilot-info.cjs', 'viepilot-update.cjs', 'viepilot-install.cjs']) {
|
|
260
|
-
steps.push({ kind: 'copy_file', from: path.join(root, 'lib', f), to: path.join(viepilotDir, 'lib', f) });
|
|
261
|
-
}
|
|
197
|
+
// chmod bin files
|
|
198
|
+
for (const f of binFiles) {
|
|
199
|
+
steps.push({ kind: 'chmod', path: path.join(vpDir, 'bin', f), mode: 0o755 });
|
|
200
|
+
}
|
|
262
201
|
|
|
263
|
-
|
|
202
|
+
// resolve {envToolDir} placeholder → adapter's actual install base (ENH-035)
|
|
264
203
|
steps.push({
|
|
265
|
-
kind: '
|
|
266
|
-
|
|
267
|
-
|
|
204
|
+
kind: 'rewrite_paths_in_dir',
|
|
205
|
+
dir: skillsDir,
|
|
206
|
+
glob: '**/*.md',
|
|
207
|
+
from: '{envToolDir}',
|
|
208
|
+
to: adapter.executionContextBase,
|
|
268
209
|
});
|
|
269
210
|
}
|
|
270
211
|
|
|
@@ -275,27 +216,43 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
|
|
|
275
216
|
'Check optional cloc for README metrics (brew/apt/dnf/choco); installation continues if missing.',
|
|
276
217
|
});
|
|
277
218
|
|
|
219
|
+
const primaryAdapter = selectedAdapters[0];
|
|
220
|
+
const primaryVpDir = primaryAdapter.viepilotDir(home);
|
|
221
|
+
|
|
278
222
|
if (wantPathShim) {
|
|
279
223
|
steps.push({
|
|
280
224
|
kind: 'path_shim',
|
|
281
225
|
links: [
|
|
282
|
-
{ path: '/usr/local/bin/vp-tools', target: path.join(
|
|
283
|
-
{ path: '/usr/local/bin/viepilot', target: path.join(
|
|
226
|
+
{ path: '/usr/local/bin/vp-tools', target: path.join(primaryVpDir, 'bin', 'vp-tools.cjs') },
|
|
227
|
+
{ path: '/usr/local/bin/viepilot', target: path.join(primaryVpDir, 'bin', 'viepilot.cjs') },
|
|
284
228
|
],
|
|
285
229
|
note: 'Unix typical; on Windows native, PATH shim may be skipped or manual.',
|
|
286
230
|
});
|
|
287
231
|
}
|
|
288
232
|
|
|
233
|
+
// ENH-032: prompt for language config at end of install
|
|
234
|
+
steps.push({
|
|
235
|
+
kind: 'language_config_prompt',
|
|
236
|
+
autoYes: env.autoYes,
|
|
237
|
+
home,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Build paths object — legacy keys preserved for backward compat with existing tests/CLI.
|
|
241
|
+
const cursorAdapter = selectedAdapters.find((a) => a.id === 'cursor');
|
|
242
|
+
const claudeAdapter = selectedAdapters.find((a) => a.id === 'claude-code');
|
|
243
|
+
|
|
289
244
|
return {
|
|
290
245
|
version: 1,
|
|
291
246
|
packageRoot: root,
|
|
292
247
|
env,
|
|
293
248
|
home,
|
|
294
249
|
paths: {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
250
|
+
skillsDir: primaryAdapter.skillsDir(home),
|
|
251
|
+
viepilotDir: primaryAdapter.viepilotDir(home),
|
|
252
|
+
// Legacy keys for backward compat:
|
|
253
|
+
cursorSkillsDir: cursorAdapter ? cursorAdapter.skillsDir(home) : null,
|
|
254
|
+
claudeSkillsDir: claudeAdapter ? claudeAdapter.skillsDir(home) : null,
|
|
255
|
+
claudeViepilotDir: claudeAdapter ? claudeAdapter.viepilotDir(home) : null,
|
|
299
256
|
viepilotUserDataDir,
|
|
300
257
|
viepilotProfilesDir,
|
|
301
258
|
viepilotProfileMapPath,
|
|
@@ -313,12 +270,15 @@ function formatPlanLines(plan) {
|
|
|
313
270
|
const lines = [];
|
|
314
271
|
lines.push('ViePilot install plan (dry-run)');
|
|
315
272
|
lines.push(` packageRoot: ${plan.packageRoot}`);
|
|
316
|
-
lines.push(` profile: ${plan.env.profile}
|
|
317
|
-
lines.push(` skills
|
|
318
|
-
if (plan.paths.
|
|
273
|
+
lines.push(` profile: ${plan.env.profile}`);
|
|
274
|
+
lines.push(` skills: ${plan.paths.skillsDir}`);
|
|
275
|
+
if (plan.paths.cursorSkillsDir && plan.paths.cursorSkillsDir !== plan.paths.skillsDir) {
|
|
276
|
+
lines.push(` skills (Cursor): ${plan.paths.cursorSkillsDir}`);
|
|
277
|
+
}
|
|
278
|
+
if (plan.paths.claudeSkillsDir && plan.paths.claudeSkillsDir !== plan.paths.skillsDir) {
|
|
319
279
|
lines.push(` skills (Claude Code): ${plan.paths.claudeSkillsDir}`);
|
|
320
280
|
}
|
|
321
|
-
if (plan.paths.claudeViepilotDir) {
|
|
281
|
+
if (plan.paths.claudeViepilotDir && plan.paths.claudeViepilotDir !== plan.paths.viepilotDir) {
|
|
322
282
|
lines.push(` viepilot (Claude Code): ${plan.paths.claudeViepilotDir}`);
|
|
323
283
|
}
|
|
324
284
|
lines.push(` viepilot: ${plan.paths.viepilotDir}`);
|
|
@@ -358,6 +318,9 @@ function formatPlanLines(plan) {
|
|
|
358
318
|
case 'rewrite_paths_in_dir':
|
|
359
319
|
lines.push(`${n}. rewrite_paths_in_dir ${s.dir}: "${s.from}" → "${s.to}" in ${s.glob}`);
|
|
360
320
|
break;
|
|
321
|
+
case 'language_config_prompt':
|
|
322
|
+
lines.push(`${n}. language_config_prompt: write ~/.viepilot/config.json (communication + document language; ${s.autoYes ? 'auto-yes → defaults' : 'interactive'})`);
|
|
323
|
+
break;
|
|
361
324
|
default:
|
|
362
325
|
lines.push(`${n}. ${JSON.stringify(s)}`);
|
|
363
326
|
}
|
|
@@ -503,7 +466,7 @@ function applyInstallPlan(plan, options = {}) {
|
|
|
503
466
|
break;
|
|
504
467
|
case 'path_shim':
|
|
505
468
|
if (process.platform === 'win32') {
|
|
506
|
-
logs.push('path_shim: skipped on Windows (add
|
|
469
|
+
logs.push('path_shim: skipped on Windows (add viepilot/bin to PATH manually if needed).');
|
|
507
470
|
break;
|
|
508
471
|
}
|
|
509
472
|
if (dryRun) {
|
|
@@ -544,6 +507,16 @@ function applyInstallPlan(plan, options = {}) {
|
|
|
544
507
|
rewriteDir(step.dir);
|
|
545
508
|
break;
|
|
546
509
|
}
|
|
510
|
+
case 'language_config_prompt': {
|
|
511
|
+
if (dryRun) {
|
|
512
|
+
logs.push(`[dry-run] language_config_prompt: would write ~/.viepilot/config.json with communication=en, document=en`);
|
|
513
|
+
break;
|
|
514
|
+
}
|
|
515
|
+
// Write defaults; future interactive installer can prompt here
|
|
516
|
+
writeConfig({ language: { communication: 'en', document: 'en' } }, step.home);
|
|
517
|
+
logs.push(`language_config_prompt: wrote ${step.home}/.viepilot/config.json (communication=en, document=en)`);
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
547
520
|
default:
|
|
548
521
|
logs.push(`unknown step kind: ${JSON.stringify(step)}`);
|
|
549
522
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viepilot",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.4.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": {
|
|
@@ -44,8 +44,6 @@
|
|
|
44
44
|
"workflows/",
|
|
45
45
|
"templates/",
|
|
46
46
|
"ui-components/",
|
|
47
|
-
"install.sh",
|
|
48
|
-
"dev-install.sh",
|
|
49
47
|
"README.md",
|
|
50
48
|
"CHANGELOG.md",
|
|
51
49
|
"LICENSE",
|
package/skills/vp-audit/SKILL.md
CHANGED
|
@@ -25,54 +25,54 @@ Use Cursor tools: `Shell`, `ReadFile`, `Glob`, `rg`, `ApplyPatch`, `WebSearch`,
|
|
|
25
25
|
<implementation_routing_guard>
|
|
26
26
|
## Implementation routing guard (ENH-021)
|
|
27
27
|
|
|
28
|
-
- **
|
|
28
|
+
- **Report / gap** — do **not** fix shipping by default; route **`/vp-request`** → **`/vp-evolve`** → **`/vp-auto`** or user explicit. See `workflows/request.md`.
|
|
29
29
|
</implementation_routing_guard>
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
<objective>
|
|
33
|
-
Audit ViePilot project state
|
|
34
|
-
|
|
35
|
-
Auto-
|
|
33
|
+
Audit ViePilot project state and documentation to detect drift.
|
|
34
|
+
Works on **any project** using ViePilot (Java, Node, Python, etc.).
|
|
35
|
+
Auto-detects if running inside the viepilot framework repo to enable framework-specific checks.
|
|
36
36
|
|
|
37
|
-
**Tier 1 — ViePilot State Consistency (
|
|
37
|
+
**Tier 1 — ViePilot State Consistency (all projects):**
|
|
38
38
|
- `.viepilot/TRACKER.md` current state vs `.viepilot/phases/*/PHASE-STATE.md`
|
|
39
39
|
- `.viepilot/ROADMAP.md` phase status vs PHASE-STATE.md
|
|
40
40
|
- `.viepilot/HANDOFF.json` vs TRACKER.md (resume-state consistency)
|
|
41
41
|
- Git tags `vp-p{N}-complete` vs completed phases in PHASE-STATE.md
|
|
42
42
|
|
|
43
|
-
**Tier 2 — Project Documentation Drift (
|
|
43
|
+
**Tier 2 — Project Documentation Drift (all projects):**
|
|
44
44
|
- `README.md` version vs `package.json` / `pom.xml` / `pyproject.toml`
|
|
45
45
|
- `CHANGELOG.md` vs recent git commits
|
|
46
|
-
- Placeholder URLs
|
|
47
|
-
-
|
|
46
|
+
- Placeholder URLs in `docs/` (`your-org`, `YOUR_USERNAME`, etc.)
|
|
47
|
+
- New features (from recent phases) without documentation
|
|
48
48
|
- `ARCHITECTURE.md` diagram applicability matrix consistency:
|
|
49
49
|
- `required` diagrams must have Mermaid content
|
|
50
50
|
- `optional` diagrams may be omitted/merged with explicit note
|
|
51
51
|
- `N/A` diagrams must have rationale line
|
|
52
52
|
- **ENH-022 (recommended check):** when a diagram type is `required` (or `optional` with a real Mermaid block) and crystallize policy applies, verify **`.viepilot/architecture/<type>.mermaid`** exists and that **Diagram source** lines in `ARCHITECTURE.md` match; for `N/A`, sidecar file should be absent (no empty stubs)
|
|
53
53
|
|
|
54
|
-
**Tier 3 — Stack Best Practices + Code Quality (
|
|
55
|
-
- Detect stacks
|
|
56
|
-
-
|
|
57
|
-
- Severity findings: `critical` / `high` / `medium` / `low`
|
|
58
|
-
- Fallback research
|
|
59
|
-
-
|
|
54
|
+
**Tier 3 — Stack Best Practices + Code Quality (all projects, for each detected stack):**
|
|
55
|
+
- Detect relevant stacks from context/project manifests
|
|
56
|
+
- Match code patterns against stack-specific Do/Don't + anti-patterns
|
|
57
|
+
- Severity findings: `critical` / `high` / `medium` / `low` with file/module mapping
|
|
58
|
+
- Fallback research using `WebSearch` + `WebFetch` when stack cache is missing/weak
|
|
59
|
+
- Generate guardrails/checklist output for `vp-auto` reuse during preflight
|
|
60
60
|
|
|
61
|
-
**Tier 4 — Framework Integrity (
|
|
62
|
-
- Auto-detect: `skills/vp-*/SKILL.md`
|
|
63
|
-
- `ARCHITECTURE.md` counts vs `skills/`, `workflows/`, CLI
|
|
61
|
+
**Tier 4 — Framework Integrity (only when viepilot framework repo is detected):**
|
|
62
|
+
- Auto-detect: `skills/vp-*/SKILL.md` present → this is the viepilot framework repo
|
|
63
|
+
- `ARCHITECTURE.md` counts vs actual `skills/`, `workflows/`, CLI
|
|
64
64
|
- `README.md` viepilot-specific badges (version, skills-N, workflows-N)
|
|
65
65
|
- `docs/skills-reference.md` sections vs `skills/` directory
|
|
66
66
|
|
|
67
67
|
**Output:**
|
|
68
|
-
-
|
|
69
|
-
- Auto-fix option
|
|
70
|
-
- Suggestions
|
|
71
|
-
- `vp-auto
|
|
68
|
+
- Report by 4 tiers, each tier with its own status
|
|
69
|
+
- Auto-fix option per tier
|
|
70
|
+
- Suggestions for complex gaps
|
|
71
|
+
- `vp-auto`-compatible guardrails contract per stack
|
|
72
72
|
</objective>
|
|
73
73
|
|
|
74
74
|
<execution_context>
|
|
75
|
-
@$HOME
|
|
75
|
+
@$HOME/{envToolDir}/workflows/audit.md
|
|
76
76
|
</execution_context>
|
|
77
77
|
|
|
78
78
|
<context>
|
|
@@ -89,7 +89,7 @@ Optional flags:
|
|
|
89
89
|
</context>
|
|
90
90
|
|
|
91
91
|
<process>
|
|
92
|
-
Execute workflow from `@$HOME
|
|
92
|
+
Execute workflow from `@$HOME/{envToolDir}/workflows/audit.md`
|
|
93
93
|
|
|
94
94
|
### Quick Summary
|
|
95
95
|
|
package/skills/vp-auto/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vp-auto
|
|
3
|
-
description: "Autonomous execution loop
|
|
3
|
+
description: "Autonomous execution loop with control points and recovery"
|
|
4
4
|
version: 0.2.2
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ version: 0.2.2
|
|
|
10
10
|
- Treat all user text after the skill mention as `{{VP_ARGS}}`
|
|
11
11
|
|
|
12
12
|
## B. User Prompting
|
|
13
|
-
Prompt user conversationally
|
|
13
|
+
Prompt user conversationally with numbered list options at control points.
|
|
14
14
|
|
|
15
15
|
## C. Tool Usage
|
|
16
16
|
Use Cursor tools: `Shell`, `ReadFile`, `Glob`, `rg`, `ApplyPatch`, `WebSearch`, `WebFetch`, `Subagent`
|
|
@@ -28,12 +28,12 @@ Use `Task(subagent_type="generalPurpose", ...)` for parallel execution.
|
|
|
28
28
|
<implementation_routing_guard>
|
|
29
29
|
## Primary implementation lane (ENH-021)
|
|
30
30
|
|
|
31
|
-
- **`/vp-auto`** + `workflows/autonomous.md`
|
|
31
|
+
- **`/vp-auto`** + `workflows/autonomous.md` is the **default lane** for **implementing** work that already has a **phase/task plan** (doc-first **BUG-001**, git persistence **BUG-003**). **`/vp-request`** and **`/vp-evolve`** do **not** replace this lane unless the user **explicitly** overrides.
|
|
32
32
|
</implementation_routing_guard>
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
<objective>
|
|
36
|
-
Autonomous execution
|
|
36
|
+
Autonomous execution of project phases. For each phase: analyze → plan → execute → verify → iterate.
|
|
37
37
|
|
|
38
38
|
Pauses at control points:
|
|
39
39
|
- Conflicts detected
|
|
@@ -88,24 +88,38 @@ If required task details are missing, do not implement until task contract is re
|
|
|
88
88
|
- `README.md` metrics — run `npm run readme:sync` when script exists; if `cloc` missing, continue with logged guidance (non-blocking)
|
|
89
89
|
|
|
90
90
|
**After:** Project built, or paused for user intervention.
|
|
91
|
+
|
|
92
|
+
**Language configuration (ENH-032):**
|
|
93
|
+
- Initialize step reads `~/.viepilot/config.json` → `COMMUNICATION_LANG` (default: `en`).
|
|
94
|
+
- `COMMUNICATION_LANG` controls banners, control-point messages, and user-facing output.
|
|
95
|
+
- Configure via: `vp-tools config set language.communication vi`
|
|
91
96
|
</objective>
|
|
92
97
|
|
|
93
98
|
<execution_context>
|
|
94
|
-
@$HOME
|
|
99
|
+
@$HOME/{envToolDir}/workflows/autonomous.md
|
|
95
100
|
</execution_context>
|
|
96
101
|
|
|
97
102
|
<context>
|
|
98
103
|
Optional flags:
|
|
99
|
-
- `--from N` : Start
|
|
100
|
-
- `--phase N` :
|
|
104
|
+
- `--from N` : Start from phase N
|
|
105
|
+
- `--phase N` : Run only phase N
|
|
101
106
|
- `--fast` : Skip optional verifications
|
|
102
107
|
- `--dry-run` : Plan only, no execution
|
|
103
108
|
|
|
104
|
-
No extra args:
|
|
109
|
+
No extra args: simply means the flags above are **off** — **not** a rule of “mandatory stop after each task”. In chat, one turn is typically ~one task; continue with the next turn or invoke `/vp-auto` again. Doc: `docs/user/features/autonomous-mode.md`.
|
|
110
|
+
|
|
111
|
+
**Task path validation (BUG-009):**
|
|
112
|
+
Before executing each task, validates all paths in the `## Paths` block.
|
|
113
|
+
If any path starts with `~/` or `/` (absolute):
|
|
114
|
+
- Execution stops for that task with a ⛔ error message
|
|
115
|
+
- User must fix the task file to use repo-relative paths before continuing
|
|
116
|
+
- This prevents accidentally editing `~/.claude/` (live install) instead of source
|
|
117
|
+
|
|
118
|
+
See preflight check in `workflows/autonomous.md` → “Preflight: Task Paths Validation (BUG-009)”.
|
|
105
119
|
</context>
|
|
106
120
|
|
|
107
121
|
<process>
|
|
108
|
-
Execute workflow from `@$HOME
|
|
122
|
+
Execute workflow from `@$HOME/{envToolDir}/workflows/autonomous.md`
|
|
109
123
|
|
|
110
124
|
### 1. Initialize
|
|
111
125
|
```bash
|