viepilot 1.14.0 → 2.1.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 +98 -0
- package/README.md +3 -3
- package/bin/viepilot.cjs +7 -5
- package/bin/vp-tools.cjs +193 -0
- package/dev-install.sh +34 -13
- package/docs/user/features/hooks.md +93 -0
- package/lib/adapters/claude-code.cjs +42 -0
- package/lib/adapters/cursor.cjs +31 -0
- package/lib/adapters/index.cjs +26 -0
- package/lib/hooks/brainstorm-staleness.cjs +231 -0
- package/lib/viepilot-config.cjs +103 -0
- package/lib/viepilot-install.cjs +128 -153
- package/package.json +1 -1
- package/skills/vp-audit/SKILL.md +21 -21
- package/skills/vp-auto/SKILL.md +21 -7
- package/skills/vp-brainstorm/SKILL.md +42 -36
- package/skills/vp-crystallize/SKILL.md +22 -16
- package/skills/vp-debug/SKILL.md +2 -2
- package/skills/vp-docs/SKILL.md +7 -7
- package/skills/vp-evolve/SKILL.md +25 -12
- package/skills/vp-info/SKILL.md +23 -23
- package/skills/vp-pause/SKILL.md +5 -5
- package/skills/vp-request/SKILL.md +12 -12
- package/skills/vp-resume/SKILL.md +4 -4
- package/skills/vp-rollback/SKILL.md +3 -3
- package/skills/vp-status/SKILL.md +4 -4
- package/skills/vp-task/SKILL.md +2 -2
- package/skills/vp-ui-components/SKILL.md +12 -12
- package/skills/vp-update/SKILL.md +17 -17
- 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 +38 -5
- package/workflows/brainstorm.md +398 -222
- package/workflows/crystallize.md +46 -33
- package/workflows/debug.md +9 -9
- package/workflows/documentation.md +5 -5
- package/workflows/evolve.md +44 -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/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,150 +131,86 @@ 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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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 });
|
|
165
|
+
}
|
|
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 });
|
|
170
|
+
}
|
|
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 });
|
|
175
|
+
}
|
|
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 });
|
|
180
|
+
}
|
|
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);
|
|
184
191
|
steps.push(ent.isDirectory() ? { kind: 'copy_dir', from: src, to: dest } : { kind: 'copy_file', from: src, to: dest });
|
|
185
192
|
}
|
|
193
|
+
}
|
|
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') });
|
|
186
196
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
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') });
|
|
197
|
+
// chmod bin files
|
|
198
|
+
for (const f of binFiles) {
|
|
199
|
+
steps.push({ kind: 'chmod', path: path.join(vpDir, 'bin', f), mode: 0o755 });
|
|
200
|
+
}
|
|
196
201
|
|
|
197
|
-
|
|
202
|
+
// path rewrite in skills (if adapter requires it — e.g. claude-code rewrites .cursor → .claude)
|
|
203
|
+
if (adapter.pathRewrite) {
|
|
198
204
|
steps.push({
|
|
199
205
|
kind: 'rewrite_paths_in_dir',
|
|
200
|
-
dir:
|
|
206
|
+
dir: skillsDir,
|
|
201
207
|
glob: '**/*.md',
|
|
202
|
-
from:
|
|
203
|
-
to:
|
|
208
|
+
from: adapter.pathRewrite.from,
|
|
209
|
+
to: adapter.pathRewrite.to,
|
|
204
210
|
});
|
|
205
211
|
}
|
|
206
212
|
}
|
|
207
213
|
|
|
208
|
-
for (const ent of listDirEntries(root, 'workflows')) {
|
|
209
|
-
const src = path.join(root, 'workflows', ent.name);
|
|
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 });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
for (const ent of listDirEntries(root, path.join('templates', 'project'))) {
|
|
219
|
-
const src = path.join(root, 'templates', 'project', ent.name);
|
|
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 });
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
for (const ent of listDirEntries(root, path.join('templates', 'phase'))) {
|
|
229
|
-
const src = path.join(root, 'templates', 'phase', ent.name);
|
|
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 });
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const uiRoot = path.join(root, 'ui-components');
|
|
239
|
-
if (fs.existsSync(uiRoot)) {
|
|
240
|
-
for (const ent of listDirEntries(root, 'ui-components')) {
|
|
241
|
-
const src = path.join(root, 'ui-components', ent.name);
|
|
242
|
-
const dest = path.join(viepilotDir, 'ui-components', ent.name);
|
|
243
|
-
if (ent.isDirectory()) {
|
|
244
|
-
steps.push({ kind: 'copy_dir', from: src, to: dest });
|
|
245
|
-
} else if (ent.isFile()) {
|
|
246
|
-
steps.push({ kind: 'copy_file', from: src, to: dest });
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const binFiles = ['vp-tools.cjs', 'viepilot.cjs'];
|
|
252
|
-
for (const f of binFiles) {
|
|
253
|
-
steps.push({
|
|
254
|
-
kind: 'copy_file',
|
|
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
|
-
}
|
|
262
|
-
|
|
263
|
-
for (const f of binFiles) {
|
|
264
|
-
steps.push({
|
|
265
|
-
kind: 'chmod',
|
|
266
|
-
path: path.join(viepilotDir, 'bin', f),
|
|
267
|
-
mode: 0o755,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
214
|
steps.push({
|
|
272
215
|
kind: 'note',
|
|
273
216
|
id: 'cloc_optional',
|
|
@@ -275,27 +218,43 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
|
|
|
275
218
|
'Check optional cloc for README metrics (brew/apt/dnf/choco); installation continues if missing.',
|
|
276
219
|
});
|
|
277
220
|
|
|
221
|
+
const primaryAdapter = selectedAdapters[0];
|
|
222
|
+
const primaryVpDir = primaryAdapter.viepilotDir(home);
|
|
223
|
+
|
|
278
224
|
if (wantPathShim) {
|
|
279
225
|
steps.push({
|
|
280
226
|
kind: 'path_shim',
|
|
281
227
|
links: [
|
|
282
|
-
{ path: '/usr/local/bin/vp-tools', target: path.join(
|
|
283
|
-
{ path: '/usr/local/bin/viepilot', target: path.join(
|
|
228
|
+
{ path: '/usr/local/bin/vp-tools', target: path.join(primaryVpDir, 'bin', 'vp-tools.cjs') },
|
|
229
|
+
{ path: '/usr/local/bin/viepilot', target: path.join(primaryVpDir, 'bin', 'viepilot.cjs') },
|
|
284
230
|
],
|
|
285
231
|
note: 'Unix typical; on Windows native, PATH shim may be skipped or manual.',
|
|
286
232
|
});
|
|
287
233
|
}
|
|
288
234
|
|
|
235
|
+
// ENH-032: prompt for language config at end of install
|
|
236
|
+
steps.push({
|
|
237
|
+
kind: 'language_config_prompt',
|
|
238
|
+
autoYes: env.autoYes,
|
|
239
|
+
home,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Build paths object — legacy keys preserved for backward compat with existing tests/CLI.
|
|
243
|
+
const cursorAdapter = selectedAdapters.find((a) => a.id === 'cursor');
|
|
244
|
+
const claudeAdapter = selectedAdapters.find((a) => a.id === 'claude-code');
|
|
245
|
+
|
|
289
246
|
return {
|
|
290
247
|
version: 1,
|
|
291
248
|
packageRoot: root,
|
|
292
249
|
env,
|
|
293
250
|
home,
|
|
294
251
|
paths: {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
252
|
+
skillsDir: primaryAdapter.skillsDir(home),
|
|
253
|
+
viepilotDir: primaryAdapter.viepilotDir(home),
|
|
254
|
+
// Legacy keys for backward compat:
|
|
255
|
+
cursorSkillsDir: cursorAdapter ? cursorAdapter.skillsDir(home) : null,
|
|
256
|
+
claudeSkillsDir: claudeAdapter ? claudeAdapter.skillsDir(home) : null,
|
|
257
|
+
claudeViepilotDir: claudeAdapter ? claudeAdapter.viepilotDir(home) : null,
|
|
299
258
|
viepilotUserDataDir,
|
|
300
259
|
viepilotProfilesDir,
|
|
301
260
|
viepilotProfileMapPath,
|
|
@@ -313,12 +272,15 @@ function formatPlanLines(plan) {
|
|
|
313
272
|
const lines = [];
|
|
314
273
|
lines.push('ViePilot install plan (dry-run)');
|
|
315
274
|
lines.push(` packageRoot: ${plan.packageRoot}`);
|
|
316
|
-
lines.push(` profile: ${plan.env.profile}
|
|
317
|
-
lines.push(` skills
|
|
318
|
-
if (plan.paths.
|
|
275
|
+
lines.push(` profile: ${plan.env.profile}`);
|
|
276
|
+
lines.push(` skills: ${plan.paths.skillsDir}`);
|
|
277
|
+
if (plan.paths.cursorSkillsDir && plan.paths.cursorSkillsDir !== plan.paths.skillsDir) {
|
|
278
|
+
lines.push(` skills (Cursor): ${plan.paths.cursorSkillsDir}`);
|
|
279
|
+
}
|
|
280
|
+
if (plan.paths.claudeSkillsDir && plan.paths.claudeSkillsDir !== plan.paths.skillsDir) {
|
|
319
281
|
lines.push(` skills (Claude Code): ${plan.paths.claudeSkillsDir}`);
|
|
320
282
|
}
|
|
321
|
-
if (plan.paths.claudeViepilotDir) {
|
|
283
|
+
if (plan.paths.claudeViepilotDir && plan.paths.claudeViepilotDir !== plan.paths.viepilotDir) {
|
|
322
284
|
lines.push(` viepilot (Claude Code): ${plan.paths.claudeViepilotDir}`);
|
|
323
285
|
}
|
|
324
286
|
lines.push(` viepilot: ${plan.paths.viepilotDir}`);
|
|
@@ -358,6 +320,9 @@ function formatPlanLines(plan) {
|
|
|
358
320
|
case 'rewrite_paths_in_dir':
|
|
359
321
|
lines.push(`${n}. rewrite_paths_in_dir ${s.dir}: "${s.from}" → "${s.to}" in ${s.glob}`);
|
|
360
322
|
break;
|
|
323
|
+
case 'language_config_prompt':
|
|
324
|
+
lines.push(`${n}. language_config_prompt: write ~/.viepilot/config.json (communication + document language; ${s.autoYes ? 'auto-yes → defaults' : 'interactive'})`);
|
|
325
|
+
break;
|
|
361
326
|
default:
|
|
362
327
|
lines.push(`${n}. ${JSON.stringify(s)}`);
|
|
363
328
|
}
|
|
@@ -503,7 +468,7 @@ function applyInstallPlan(plan, options = {}) {
|
|
|
503
468
|
break;
|
|
504
469
|
case 'path_shim':
|
|
505
470
|
if (process.platform === 'win32') {
|
|
506
|
-
logs.push('path_shim: skipped on Windows (add
|
|
471
|
+
logs.push('path_shim: skipped on Windows (add viepilot/bin to PATH manually if needed).');
|
|
507
472
|
break;
|
|
508
473
|
}
|
|
509
474
|
if (dryRun) {
|
|
@@ -544,6 +509,16 @@ function applyInstallPlan(plan, options = {}) {
|
|
|
544
509
|
rewriteDir(step.dir);
|
|
545
510
|
break;
|
|
546
511
|
}
|
|
512
|
+
case 'language_config_prompt': {
|
|
513
|
+
if (dryRun) {
|
|
514
|
+
logs.push(`[dry-run] language_config_prompt: would write ~/.viepilot/config.json with communication=en, document=en`);
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
// Write defaults; future interactive installer can prompt here
|
|
518
|
+
writeConfig({ language: { communication: 'en', document: 'en' } }, step.home);
|
|
519
|
+
logs.push(`language_config_prompt: wrote ${step.home}/.viepilot/config.json (communication=en, document=en)`);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
547
522
|
default:
|
|
548
523
|
logs.push(`unknown step kind: ${JSON.stringify(step)}`);
|
|
549
524
|
}
|
package/package.json
CHANGED
package/skills/vp-audit/SKILL.md
CHANGED
|
@@ -25,50 +25,50 @@ 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>
|
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,6 +88,11 @@ 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>
|
|
@@ -96,12 +101,21 @@ If required task details are missing, do not implement until task contract is re
|
|
|
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>
|