viepilot 2.45.3 → 2.45.5
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 +19 -0
- package/bin/viepilot.cjs +35 -2
- package/lib/viepilot-install.cjs +7 -5
- package/package.json +1 -1
- package/workflows/crystallize.md +30 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.45.5] - 2026-04-27
|
|
11
|
+
|
|
12
|
+
### Enhanced
|
|
13
|
+
- **ENH-078**: `npx viepilot install` now prompts users to select their preferred
|
|
14
|
+
communication language (the language ViePilot uses for banners and AI prompts)
|
|
15
|
+
via keyboard selector or numbered-list fallback; chosen language written to
|
|
16
|
+
`~/.viepilot/config.json → language.communication`; supports 10 languages
|
|
17
|
+
(en, vi, fr, ja, de, es, zh, ko, pt, id); `--yes` mode skips prompt and
|
|
18
|
+
defaults to `en` (ENH-078)
|
|
19
|
+
|
|
20
|
+
## [2.45.4] - 2026-04-27
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- **BUG-025**: brownfield crystallize initial mode-selection prompt ("Proceed / Run brainstorm
|
|
24
|
+
first / Cancel") was rendered as plain-text numbered list on Claude Code terminal because
|
|
25
|
+
`workflows/crystallize.md` Step 0-B had no AUQ spec for the auto-detected entry gate.
|
|
26
|
+
Fix: added adapter-aware `AskUserQuestion` block with 3 labelled options before scanner
|
|
27
|
+
execution; text fallback preserved for Cursor/Codex/Antigravity (BUG-025)
|
|
28
|
+
|
|
10
29
|
## [2.45.3] - 2026-04-25
|
|
11
30
|
|
|
12
31
|
### Fixed
|
package/bin/viepilot.cjs
CHANGED
|
@@ -17,6 +17,19 @@ const { buildInstallPlan, applyInstallPlan, resolveViepilotPackageRoot } = requi
|
|
|
17
17
|
const { adapters: adapterMap } = require(path.join(__dirname, '..', 'lib', 'adapters', 'index.cjs'));
|
|
18
18
|
|
|
19
19
|
// UI target list — keep cursor-agent and cursor-ide as distinct choices for users.
|
|
20
|
+
const LANGUAGES = [
|
|
21
|
+
{ id: 'en', label: 'English (en)' },
|
|
22
|
+
{ id: 'vi', label: 'Vietnamese — Tiếng Việt (vi)' },
|
|
23
|
+
{ id: 'fr', label: 'French — Français (fr)' },
|
|
24
|
+
{ id: 'ja', label: 'Japanese — 日本語 (ja)' },
|
|
25
|
+
{ id: 'de', label: 'German — Deutsch (de)' },
|
|
26
|
+
{ id: 'es', label: 'Spanish — Español (es)' },
|
|
27
|
+
{ id: 'zh', label: 'Chinese Simplified — 中文 (zh)' },
|
|
28
|
+
{ id: 'ko', label: 'Korean — 한국어 (ko)' },
|
|
29
|
+
{ id: 'pt', label: 'Portuguese — Português (pt)' },
|
|
30
|
+
{ id: 'id', label: 'Indonesian — Bahasa Indonesia (id)' },
|
|
31
|
+
];
|
|
32
|
+
|
|
20
33
|
const TARGETS = [
|
|
21
34
|
{ id: 'claude-code', label: adapterMap['claude-code'].name + ' (default)' },
|
|
22
35
|
{ id: 'cursor-agent', label: 'Cursor Agent' },
|
|
@@ -235,6 +248,19 @@ function ask(question) {
|
|
|
235
248
|
});
|
|
236
249
|
}
|
|
237
250
|
|
|
251
|
+
async function interactiveLanguageSelection() {
|
|
252
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
253
|
+
console.log('\nSelect communication language (ViePilot banners and prompts):');
|
|
254
|
+
LANGUAGES.forEach((l, idx) => console.log(` ${idx + 1}. ${l.label}`));
|
|
255
|
+
const answer = await ask('Language [1 = English]: ');
|
|
256
|
+
const idx = parseInt(answer, 10);
|
|
257
|
+
const lang = LANGUAGES[Number.isInteger(idx) && idx >= 1 && idx <= LANGUAGES.length ? idx - 1 : 0];
|
|
258
|
+
return lang.id;
|
|
259
|
+
}
|
|
260
|
+
const selected = await runKeyboardSelector(LANGUAGES, 'single', 'Select communication language');
|
|
261
|
+
return (selected && selected[0]) || 'en';
|
|
262
|
+
}
|
|
263
|
+
|
|
238
264
|
async function interactiveTargetSelection() {
|
|
239
265
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
240
266
|
console.log('\nSelect install targets (comma-separated numbers):');
|
|
@@ -261,7 +287,7 @@ async function interactiveTargetSelection() {
|
|
|
261
287
|
* @param {boolean} dryRun
|
|
262
288
|
* @returns {{ ok: boolean, code: number }}
|
|
263
289
|
*/
|
|
264
|
-
function runInstallViaNode(selectedTargets, dryRun) {
|
|
290
|
+
function runInstallViaNode(selectedTargets, dryRun, communicationLang = 'en') {
|
|
265
291
|
const fallbackRoot = path.join(__dirname, '..');
|
|
266
292
|
const pkgRoot = resolveViepilotPackageRoot(fallbackRoot) || fallbackRoot;
|
|
267
293
|
const profile = selectedTargets[0] || 'claude-code';
|
|
@@ -269,6 +295,7 @@ function runInstallViaNode(selectedTargets, dryRun) {
|
|
|
269
295
|
...process.env,
|
|
270
296
|
VIEPILOT_AUTO_YES: '1',
|
|
271
297
|
VIEPILOT_INSTALL_PROFILE: profile,
|
|
298
|
+
VIEPILOT_COMM_LANG: communicationLang,
|
|
272
299
|
};
|
|
273
300
|
const wantPathShim = env.VIEPILOT_ADD_PATH === '1';
|
|
274
301
|
|
|
@@ -328,8 +355,14 @@ async function installCommand(rawArgs) {
|
|
|
328
355
|
}
|
|
329
356
|
}
|
|
330
357
|
|
|
358
|
+
let communicationLang = 'en';
|
|
359
|
+
if (!options.yes) {
|
|
360
|
+
communicationLang = await interactiveLanguageSelection();
|
|
361
|
+
}
|
|
362
|
+
|
|
331
363
|
console.log(`\nSelected targets: ${selectedTargets.join(', ')}`);
|
|
332
|
-
|
|
364
|
+
console.log(`Communication language: ${communicationLang}`);
|
|
365
|
+
const run = runInstallViaNode(selectedTargets, options.dryRun, communicationLang);
|
|
333
366
|
const results = selectedTargets.map((target) => ({
|
|
334
367
|
ok: run.ok,
|
|
335
368
|
target,
|
package/lib/viepilot-install.cjs
CHANGED
|
@@ -29,6 +29,7 @@ function normalizeInstallEnv(envSource = process.env) {
|
|
|
29
29
|
profile: envSource.VIEPILOT_INSTALL_PROFILE || 'claude-code',
|
|
30
30
|
addPath: envSource.VIEPILOT_ADD_PATH === '1',
|
|
31
31
|
symlinkSkills: envSource.VIEPILOT_SYMLINK_SKILLS === '1',
|
|
32
|
+
communicationLang: envSource.VIEPILOT_COMM_LANG || 'en',
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -241,9 +242,10 @@ function buildInstallPlan(packageRoot, envSource = process.env, opts = {}) {
|
|
|
241
242
|
});
|
|
242
243
|
}
|
|
243
244
|
|
|
244
|
-
// ENH-032:
|
|
245
|
+
// ENH-032 / ENH-078: write selected communication language; lang chosen interactively in CLI
|
|
245
246
|
steps.push({
|
|
246
247
|
kind: 'language_config_prompt',
|
|
248
|
+
communicationLang: env.communicationLang,
|
|
247
249
|
autoYes: env.autoYes,
|
|
248
250
|
home,
|
|
249
251
|
});
|
|
@@ -519,13 +521,13 @@ function applyInstallPlan(plan, options = {}) {
|
|
|
519
521
|
break;
|
|
520
522
|
}
|
|
521
523
|
case 'language_config_prompt': {
|
|
524
|
+
const commLang = step.communicationLang ?? 'en';
|
|
522
525
|
if (dryRun) {
|
|
523
|
-
logs.push(`[dry-run] language_config_prompt: would write ~/.viepilot/config.json with communication
|
|
526
|
+
logs.push(`[dry-run] language_config_prompt: would write ~/.viepilot/config.json with communication=${commLang}, document=en`);
|
|
524
527
|
break;
|
|
525
528
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
logs.push(`language_config_prompt: wrote ${step.home}/.viepilot/config.json (communication=en, document=en)`);
|
|
529
|
+
writeConfig({ language: { communication: commLang, document: 'en' } }, step.home);
|
|
530
|
+
logs.push(`language_config_prompt: wrote ${step.home}/.viepilot/config.json (communication=${commLang}, document=en)`);
|
|
529
531
|
break;
|
|
530
532
|
}
|
|
531
533
|
default:
|
package/package.json
CHANGED
package/workflows/crystallize.md
CHANGED
|
@@ -238,6 +238,36 @@ Store all metadata for template generation.
|
|
|
238
238
|
>
|
|
239
239
|
> Ask: "Continue? (y/n)" — abort if n.
|
|
240
240
|
|
|
241
|
+
**Initial brownfield entry gate (BUG-025) — auto-detected only (no explicit `--brownfield` flag):**
|
|
242
|
+
|
|
243
|
+
When brownfield was triggered automatically (not via `--brownfield`), present the mode-selection choice **before** running the scanner:
|
|
244
|
+
|
|
245
|
+
> **Claude Code (terminal) — REQUIRED:** Call `AskUserQuestion` tool. Only fall back to text menu if the tool errors or is unavailable. AUQ spec:
|
|
246
|
+
> - question: "No brainstorm session found — this looks like an existing project. How would you like to proceed?"
|
|
247
|
+
> - header: "Brownfield Mode Detected"
|
|
248
|
+
> - options:
|
|
249
|
+
> - label: "Proceed with Brownfield Mode (Recommended)"
|
|
250
|
+
> description: "Scan codebase across 12 signal categories → auto-generate .viepilot/ artifacts"
|
|
251
|
+
> - label: "Run brainstorm first → /vp-brainstorm"
|
|
252
|
+
> description: "Capture vision/scope manually, then run /vp-crystallize to convert"
|
|
253
|
+
> - label: "Cancel"
|
|
254
|
+
> description: "Exit without changes"
|
|
255
|
+
> - multiSelect: false
|
|
256
|
+
>
|
|
257
|
+
> **Cursor / Codex / Antigravity / other:** use text menu below:
|
|
258
|
+
> ```
|
|
259
|
+
> No brainstorm session found — existing project detected.
|
|
260
|
+
> 1. Proceed with Brownfield Mode — scan across 12 signal categories → generate .viepilot/ artifacts
|
|
261
|
+
> 2. Run brainstorm first — /vp-brainstorm to capture vision/scope, then /vp-crystallize
|
|
262
|
+
> 3. Cancel — exit without changes
|
|
263
|
+
> Which would you like? (1 / 2 / 3)
|
|
264
|
+
> ```
|
|
265
|
+
>
|
|
266
|
+
> **On selection:**
|
|
267
|
+
> - "Proceed with Brownfield Mode" / "1" → continue to scanner below
|
|
268
|
+
> - "Run brainstorm first" / "2" → print: "Run `/vp-brainstorm` to capture project vision, then `/vp-crystallize` to generate .viepilot/ artifacts." and exit
|
|
269
|
+
> - "Cancel" / "3" → exit without changes
|
|
270
|
+
|
|
241
271
|
**When brownfield mode is active:**
|
|
242
272
|
1. Run the full 12-category codebase scanner (Signal Categories 1–12 below).
|
|
243
273
|
2. Produce a structured **Scan Report** (see schema at end of this step).
|