viepilot 3.9.0 → 3.10.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 +24 -0
- package/bin/vp-tools.cjs +50 -4
- package/lib/context-file-generators.cjs +147 -0
- package/package.json +1 -1
- package/workflows/crystallize.md +35 -3
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## [3.10.0] - 2026-05-25
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- ENH-101: `vp-crystallize` now generates adapter-specific AI context files at Step 1F
|
|
16
|
+
- ENH-101: New `vp-tools context-files` subcommand generates CLAUDE.md (Claude Code),
|
|
17
|
+
GEMINI.md (Antigravity), AGENTS.md (Codex), .cursorrules + .cursor/rules/ (Cursor),
|
|
18
|
+
.github/copilot-instructions.md (Copilot) from `.viepilot/` sources
|
|
19
|
+
- ENH-101: `--all` flag generates all 5 adapter files simultaneously
|
|
20
|
+
- ENH-101: Content sourced from AI-GUIDE.md, PROJECT-CONTEXT.md, SYSTEM-RULES.md, STACKS.md
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## [3.9.1] - 2026-05-25
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- BUG-031: `vp-tools hooks install` wrote wrong hook path (`~/.viepilot/hooks/
|
|
28
|
+
brainstorm-staleness.cjs`) which does not exist; corrected to
|
|
29
|
+
`{adapter.viepilotDir}/lib/hooks/brainstorm-staleness.cjs`; Stop hook no longer
|
|
30
|
+
exits non-zero each turn
|
|
31
|
+
- BUG-031: `vp-tools hooks install` (re-run) now detects and removes stale wrong-path
|
|
32
|
+
entries from settings.json before writing the correct entry
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
12
36
|
## [3.9.0] - 2026-05-24
|
|
13
37
|
|
|
14
38
|
### Changed
|
package/bin/vp-tools.cjs
CHANGED
|
@@ -1007,7 +1007,7 @@ ${colors.cyan}Examples:${colors.reset}
|
|
|
1007
1007
|
matcher: {},
|
|
1008
1008
|
hooks: [{
|
|
1009
1009
|
type: 'command',
|
|
1010
|
-
command: `node ${path.join(home, '
|
|
1010
|
+
command: `node ${path.join(adapter.viepilotDir(home), 'lib', 'hooks', 'brainstorm-staleness.cjs')}`
|
|
1011
1011
|
}]
|
|
1012
1012
|
}]
|
|
1013
1013
|
}
|
|
@@ -1024,7 +1024,7 @@ ${colors.cyan}Examples:${colors.reset}
|
|
|
1024
1024
|
}
|
|
1025
1025
|
const home = os.homedir();
|
|
1026
1026
|
const configPath = adapter.hooks.configFile(home);
|
|
1027
|
-
const hookCommand = `node ${path.join(home, '
|
|
1027
|
+
const hookCommand = `node ${path.join(adapter.viepilotDir(home), 'lib', 'hooks', 'brainstorm-staleness.cjs')}`;
|
|
1028
1028
|
|
|
1029
1029
|
// Read existing settings.json (create if missing)
|
|
1030
1030
|
let settings = {};
|
|
@@ -1032,15 +1032,22 @@ ${colors.cyan}Examples:${colors.reset}
|
|
|
1032
1032
|
try { settings = JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch (_e) { settings = {}; }
|
|
1033
1033
|
}
|
|
1034
1034
|
|
|
1035
|
-
// Merge hook entry — idempotent check
|
|
1035
|
+
// Merge hook entry — migration + idempotent check
|
|
1036
1036
|
if (!settings.hooks) settings.hooks = {};
|
|
1037
1037
|
if (!settings.hooks.Stop) settings.hooks.Stop = [];
|
|
1038
1038
|
|
|
1039
|
+
// Step A: remove any stale entry with the OLD wrong path
|
|
1040
|
+
const wrongPath = `node ${path.join(home, '.viepilot', 'hooks', 'brainstorm-staleness.cjs')}`;
|
|
1041
|
+
settings.hooks.Stop = settings.hooks.Stop.filter((entry) =>
|
|
1042
|
+
!(Array.isArray(entry.hooks) &&
|
|
1043
|
+
entry.hooks.some((h) => h.type === 'command' && h.command === wrongPath))
|
|
1044
|
+
);
|
|
1045
|
+
|
|
1046
|
+
// Step B: idempotent check for correct path
|
|
1039
1047
|
const alreadyInstalled = settings.hooks.Stop.some((entry) =>
|
|
1040
1048
|
Array.isArray(entry.hooks) &&
|
|
1041
1049
|
entry.hooks.some((h) => h.type === 'command' && h.command === hookCommand)
|
|
1042
1050
|
);
|
|
1043
|
-
|
|
1044
1051
|
if (alreadyInstalled) {
|
|
1045
1052
|
console.log(formatSuccess('ViePilot staleness hook already installed.'));
|
|
1046
1053
|
console.log(` Config: ${configPath}`);
|
|
@@ -1203,6 +1210,44 @@ ${colors.cyan}Examples:${colors.reset}
|
|
|
1203
1210
|
});
|
|
1204
1211
|
},
|
|
1205
1212
|
|
|
1213
|
+
/**
|
|
1214
|
+
* ENH-101: Generate adapter context files (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, .github/copilot-instructions.md)
|
|
1215
|
+
* Usage: vp-tools context-files [--all]
|
|
1216
|
+
*/
|
|
1217
|
+
'context-files': (args) => {
|
|
1218
|
+
const { generateAll, generateClaudeMd, generateGeminiMd, generateAgentsMd,
|
|
1219
|
+
generateCursorRules, generateCursorMdc, generateCopilotInstructions }
|
|
1220
|
+
= require('../lib/context-file-generators.cjs');
|
|
1221
|
+
const allFlag = args.includes('--all');
|
|
1222
|
+
const projectRoot = process.cwd();
|
|
1223
|
+
|
|
1224
|
+
// detect adapter
|
|
1225
|
+
const adapterCtx = require('../lib/adapter-context.cjs');
|
|
1226
|
+
const adapterId = adapterCtx.detectAdapter ? adapterCtx.detectAdapter() : 'claude-code';
|
|
1227
|
+
|
|
1228
|
+
const targets = allFlag ? generateAll(projectRoot) : (() => {
|
|
1229
|
+
const map = {
|
|
1230
|
+
'claude-code': [{ path: 'CLAUDE.md', content: generateClaudeMd(projectRoot) }],
|
|
1231
|
+
'antigravity': [{ path: 'GEMINI.md', content: generateGeminiMd(projectRoot) }],
|
|
1232
|
+
'codex': [{ path: 'AGENTS.md', content: generateAgentsMd(projectRoot) }],
|
|
1233
|
+
'cursor-agent': [
|
|
1234
|
+
{ path: '.cursorrules', content: generateCursorRules(projectRoot) },
|
|
1235
|
+
{ path: '.cursor/rules/viepilot-context.mdc', content: generateCursorMdc(projectRoot) },
|
|
1236
|
+
],
|
|
1237
|
+
'copilot': [{ path: '.github/copilot-instructions.md', content: generateCopilotInstructions(projectRoot) }],
|
|
1238
|
+
};
|
|
1239
|
+
return map[adapterId] || map['claude-code'];
|
|
1240
|
+
})();
|
|
1241
|
+
|
|
1242
|
+
for (const { path: relPath, content } of targets) {
|
|
1243
|
+
const absPath = require('path').join(projectRoot, relPath);
|
|
1244
|
+
require('fs').mkdirSync(require('path').dirname(absPath), { recursive: true });
|
|
1245
|
+
require('fs').writeFileSync(absPath, content, 'utf8');
|
|
1246
|
+
console.log(formatSuccess(`Written: ${relPath}`));
|
|
1247
|
+
}
|
|
1248
|
+
process.exit(0);
|
|
1249
|
+
},
|
|
1250
|
+
|
|
1206
1251
|
/**
|
|
1207
1252
|
* ENH-073: Manage cross-project personas.
|
|
1208
1253
|
* persona get → print active persona JSON
|
|
@@ -1620,6 +1665,7 @@ ${colors.cyan}Commands:${colors.reset}
|
|
|
1620
1665
|
${colors.bold}get-registry${colors.reset} [--id <id>] Output global skill registry as JSON
|
|
1621
1666
|
${colors.bold}scan-skills${colors.reset} Scan installed skills → ~/.viepilot/skill-registry.json
|
|
1622
1667
|
${colors.bold}check-update${colors.reset} [--silent] Check for latest ViePilot version on npm (24h cached)
|
|
1668
|
+
${colors.bold}context-files${colors.reset} [--all] Generate adapter context files (CLAUDE.md, GEMINI.md, etc.)
|
|
1623
1669
|
${colors.bold}persona${colors.reset} <op> Manage user personas (get|infer|list|set|auto-switch|context)
|
|
1624
1670
|
${colors.bold}detect-adapter${colors.reset} [--json] Detect active adapter (claude-code/cursor/antigravity/codex/copilot)
|
|
1625
1671
|
${colors.bold}validate${colors.reset} --adapter <id> Validate adapter capability requirements; exits 1 on critical gaps
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Read a .viepilot/ source file, return '' if missing.
|
|
7
|
+
*/
|
|
8
|
+
function readSource(projectRoot, relPath) {
|
|
9
|
+
try {
|
|
10
|
+
return fs.readFileSync(path.join(projectRoot, relPath), 'utf8');
|
|
11
|
+
} catch { return ''; }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Build the shared core block used by all adapters.
|
|
16
|
+
* Sources: AI-GUIDE.md, PROJECT-CONTEXT.md, SYSTEM-RULES.md, STACKS.md
|
|
17
|
+
*/
|
|
18
|
+
function buildCoreBlock(projectRoot) {
|
|
19
|
+
const meta = readSource(projectRoot, '.viepilot/PROJECT-META.md');
|
|
20
|
+
const guide = readSource(projectRoot, '.viepilot/AI-GUIDE.md');
|
|
21
|
+
const context = readSource(projectRoot, '.viepilot/PROJECT-CONTEXT.md');
|
|
22
|
+
const rules = readSource(projectRoot, '.viepilot/SYSTEM-RULES.md');
|
|
23
|
+
const stacks = readSource(projectRoot, '.viepilot/STACKS.md');
|
|
24
|
+
|
|
25
|
+
// Extract project name from PROJECT-META.md header or package.json
|
|
26
|
+
let projectName = 'Project';
|
|
27
|
+
const nameMatch = meta.match(/^#\s+(.+)/m);
|
|
28
|
+
if (nameMatch) projectName = nameMatch[1].trim();
|
|
29
|
+
else {
|
|
30
|
+
try {
|
|
31
|
+
projectName = require(path.join(projectRoot, 'package.json')).name || 'Project';
|
|
32
|
+
} catch { /* noop */ }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return { projectName, guide, context, rules, stacks };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* CLAUDE.md — Claude Code context file (full Markdown, no frontmatter)
|
|
40
|
+
*/
|
|
41
|
+
function generateClaudeMd(projectRoot) {
|
|
42
|
+
const { projectName, guide, context, rules, stacks } = buildCoreBlock(projectRoot);
|
|
43
|
+
const sections = [];
|
|
44
|
+
sections.push(`# ${projectName} — Claude Code Context\n`);
|
|
45
|
+
if (guide) sections.push(`## Navigation\n\n${guide}`);
|
|
46
|
+
if (context) sections.push(`## Domain Context\n\n${context}`);
|
|
47
|
+
if (rules) sections.push(`## Coding Standards\n\n${rules}`);
|
|
48
|
+
if (stacks) sections.push(`## Stack\n\n${stacks}`);
|
|
49
|
+
sections.push(`\n## ViePilot Workflow\n\n` +
|
|
50
|
+
`- Run \`/vp-auto\` to execute planned phases\n` +
|
|
51
|
+
`- Run \`/vp-request\` to log bugs or features\n` +
|
|
52
|
+
`- Current state: \`.viepilot/TRACKER.md\`\n`);
|
|
53
|
+
return sections.join('\n\n---\n\n');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* GEMINI.md — Antigravity / Gemini CLI context file
|
|
58
|
+
*/
|
|
59
|
+
function generateGeminiMd(projectRoot) {
|
|
60
|
+
// Same structure as CLAUDE.md; different header note
|
|
61
|
+
const content = generateClaudeMd(projectRoot);
|
|
62
|
+
return content.replace('Claude Code Context', 'Gemini / Antigravity Context');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* AGENTS.md — Codex CLI context file
|
|
67
|
+
* Codex is patch-based + sequential; emphasize apply_patch conventions
|
|
68
|
+
*/
|
|
69
|
+
function generateAgentsMd(projectRoot) {
|
|
70
|
+
const { projectName, context, rules, stacks } = buildCoreBlock(projectRoot);
|
|
71
|
+
const sections = [];
|
|
72
|
+
sections.push(`# ${projectName} — Codex Agent Instructions\n`);
|
|
73
|
+
sections.push(`## Conventions\n\n` +
|
|
74
|
+
`- Use \`apply_patch\` for all file edits\n` +
|
|
75
|
+
`- No interactive prompts — work sequentially\n` +
|
|
76
|
+
`- Commit after each logical unit\n`);
|
|
77
|
+
if (context) sections.push(`## Domain Context\n\n${context}`);
|
|
78
|
+
if (rules) sections.push(`## Coding Standards\n\n${rules}`);
|
|
79
|
+
if (stacks) sections.push(`## Stack\n\n${stacks}`);
|
|
80
|
+
sections.push(`\n## ViePilot\n\nPhase state: \`.viepilot/TRACKER.md\`\n`);
|
|
81
|
+
return sections.join('\n\n---\n\n');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* .cursorrules — Cursor legacy flat-file format
|
|
86
|
+
*/
|
|
87
|
+
function generateCursorRules(projectRoot) {
|
|
88
|
+
const { projectName, context, rules, stacks } = buildCoreBlock(projectRoot);
|
|
89
|
+
const parts = [`# ${projectName} — Cursor Rules\n`];
|
|
90
|
+
if (rules) parts.push(rules);
|
|
91
|
+
if (context) parts.push(`## Domain\n\n${context}`);
|
|
92
|
+
if (stacks) parts.push(`## Stack\n\n${stacks}`);
|
|
93
|
+
return parts.join('\n\n');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* .cursor/rules/viepilot-context.mdc — Cursor new MDC format
|
|
98
|
+
*/
|
|
99
|
+
function generateCursorMdc(projectRoot) {
|
|
100
|
+
const body = generateCursorRules(projectRoot)
|
|
101
|
+
.replace(/^# .+\n/, ''); // strip header — MDC description field covers it
|
|
102
|
+
const { projectName } = buildCoreBlock(projectRoot);
|
|
103
|
+
return `---
|
|
104
|
+
description: ${projectName} coding standards and architecture context
|
|
105
|
+
globs: ["**/*"]
|
|
106
|
+
alwaysApply: true
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
${body}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* .github/copilot-instructions.md — GitHub Copilot
|
|
114
|
+
* Copilot has shorter context; be concise, focus on coding standards
|
|
115
|
+
*/
|
|
116
|
+
function generateCopilotInstructions(projectRoot) {
|
|
117
|
+
const { projectName, rules, stacks } = buildCoreBlock(projectRoot);
|
|
118
|
+
const parts = [`# Copilot Instructions — ${projectName}\n`];
|
|
119
|
+
if (rules) parts.push(rules);
|
|
120
|
+
if (stacks) parts.push(`## Stack\n\n${stacks}`);
|
|
121
|
+
return parts.join('\n\n');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Generate all 5 adapter context files.
|
|
126
|
+
* Returns { path: string, content: string }[] — caller writes them.
|
|
127
|
+
*/
|
|
128
|
+
function generateAll(projectRoot) {
|
|
129
|
+
return [
|
|
130
|
+
{ path: 'CLAUDE.md', content: generateClaudeMd(projectRoot) },
|
|
131
|
+
{ path: 'GEMINI.md', content: generateGeminiMd(projectRoot) },
|
|
132
|
+
{ path: 'AGENTS.md', content: generateAgentsMd(projectRoot) },
|
|
133
|
+
{ path: '.cursorrules', content: generateCursorRules(projectRoot) },
|
|
134
|
+
{ path: '.cursor/rules/viepilot-context.mdc', content: generateCursorMdc(projectRoot) },
|
|
135
|
+
{ path: '.github/copilot-instructions.md', content: generateCopilotInstructions(projectRoot) },
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = {
|
|
140
|
+
generateClaudeMd,
|
|
141
|
+
generateGeminiMd,
|
|
142
|
+
generateAgentsMd,
|
|
143
|
+
generateCursorRules,
|
|
144
|
+
generateCursorMdc,
|
|
145
|
+
generateCopilotInstructions,
|
|
146
|
+
generateAll,
|
|
147
|
+
};
|
package/package.json
CHANGED
package/workflows/crystallize.md
CHANGED
|
@@ -2172,8 +2172,40 @@ Append to `.viepilot/PROJECT-CONTEXT.md`:
|
|
|
2172
2172
|
**Lock semantics**: once written, `## Skills` is the authoritative skill decision for the project. `vp-auto` reads it and **never re-prompts**.
|
|
2173
2173
|
</step>
|
|
2174
2174
|
|
|
2175
|
+
<step name="adapter_context_files">
|
|
2176
|
+
## Step 1F: Generate Adapter Context Files (ENH-101)
|
|
2177
|
+
|
|
2178
|
+
Generate the native AI context file for the active adapter so it starts with full project context.
|
|
2179
|
+
|
|
2180
|
+
**Detect adapter and generate:**
|
|
2181
|
+
```bash
|
|
2182
|
+
node bin/vp-tools.cjs context-files
|
|
2183
|
+
# or with --all to generate all 5 adapters at once:
|
|
2184
|
+
node bin/vp-tools.cjs context-files --all
|
|
2185
|
+
```
|
|
2186
|
+
|
|
2187
|
+
**What gets generated:**
|
|
2188
|
+
| Adapter | File |
|
|
2189
|
+
|---------|------|
|
|
2190
|
+
| Claude Code | `CLAUDE.md` (project root) |
|
|
2191
|
+
| Cursor | `.cursorrules` + `.cursor/rules/viepilot-context.mdc` |
|
|
2192
|
+
| Codex | `AGENTS.md` (project root) |
|
|
2193
|
+
| Antigravity | `GEMINI.md` (project root) |
|
|
2194
|
+
| GitHub Copilot | `.github/copilot-instructions.md` |
|
|
2195
|
+
|
|
2196
|
+
**Content sources** (from `.viepilot/` — skip if not yet generated):
|
|
2197
|
+
- `AI-GUIDE.md` → navigation + architecture summary
|
|
2198
|
+
- `PROJECT-CONTEXT.md` → domain knowledge, business rules
|
|
2199
|
+
- `SYSTEM-RULES.md` → coding standards, patterns
|
|
2200
|
+
- `STACKS.md` → tech stack, versions
|
|
2201
|
+
|
|
2202
|
+
**Note**: Re-running overwrites existing files with latest `.viepilot/` content.
|
|
2203
|
+
Step 1F is non-blocking — if `.viepilot/` sources are incomplete, outputs a partial file
|
|
2204
|
+
with a `<!-- viepilot: incomplete -->` comment at the top as a re-run reminder.
|
|
2205
|
+
</step>
|
|
2206
|
+
|
|
2175
2207
|
<step name="cross_reference_gate">
|
|
2176
|
-
## Step
|
|
2208
|
+
## Step 1G: Cross-Reference Gate (ENH-064)
|
|
2177
2209
|
|
|
2178
2210
|
Run when BOTH `architect_read_complete: true` AND `ui_direction_read_complete: true` are set in working notes:
|
|
2179
2211
|
|
|
@@ -2208,9 +2240,9 @@ Run when BOTH `architect_read_complete: true` AND `ui_direction_read_complete: t
|
|
|
2208
2240
|
<step name="stakeholder_review_gate">
|
|
2209
2241
|
---
|
|
2210
2242
|
|
|
2211
|
-
## Step
|
|
2243
|
+
## Step 1H: Stakeholder Review Gate (ENH-098)
|
|
2212
2244
|
|
|
2213
|
-
**Trigger**: Runs automatically after Step
|
|
2245
|
+
**Trigger**: Runs automatically after Step 1G, before Step 2.
|
|
2214
2246
|
|
|
2215
2247
|
**Skip conditions**:
|
|
2216
2248
|
- `--no-stakeholders` flag passed to `/vp-crystallize`
|