viepilot 2.4.0 → 2.15.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 +206 -0
- package/README.md +16 -13
- package/docs/brainstorm/session-2026-04-11.md +194 -0
- package/docs/skills-reference.md +58 -0
- package/docs/user/features/interactive-prompts.md +83 -0
- package/docs/user/features/proposal.md +196 -0
- package/lib/google-slides-exporter.cjs +80 -0
- package/lib/proposal-generator.cjs +249 -0
- package/lib/screenshot-artifact.cjs +142 -0
- package/lib/viepilot-config.cjs +32 -1
- package/package.json +8 -1
- package/skills/vp-audit/SKILL.md +11 -0
- package/skills/vp-brainstorm/SKILL.md +21 -0
- package/skills/vp-crystallize/SKILL.md +64 -0
- package/skills/vp-docs/SKILL.md +16 -6
- package/skills/vp-proposal/SKILL.md +175 -0
- package/skills/vp-request/SKILL.md +22 -0
- package/templates/proposal/docx/project-detail.docx +0 -0
- package/templates/proposal/pptx/general.pptx +0 -0
- package/templates/proposal/pptx/product-pitch.pptx +0 -0
- package/templates/proposal/pptx/project-proposal-creative.pptx +0 -0
- package/templates/proposal/pptx/project-proposal-enterprise.pptx +0 -0
- package/templates/proposal/pptx/project-proposal-modern-tech.pptx +0 -0
- package/templates/proposal/pptx/project-proposal.pptx +0 -0
- package/templates/proposal/pptx/tech-architecture.pptx +0 -0
- package/workflows/brainstorm.md +26 -0
- package/workflows/crystallize.md +700 -1
- package/workflows/documentation.md +26 -11
- package/workflows/evolve.md +36 -0
- package/workflows/proposal.md +807 -0
- package/workflows/request.md +35 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* screenshot-artifact.cjs
|
|
4
|
+
* ENH-042 + ENH-043: Optional screenshot/render utility for vp-proposal visual embedding.
|
|
5
|
+
*
|
|
6
|
+
* - puppeteer (optional): screenshots HTML artifact files → PNG
|
|
7
|
+
* - mmdc CLI (optional): renders Mermaid source → PNG
|
|
8
|
+
* Both return null gracefully when the tool is absent — no crash, no hard dep.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* const { screenshotArtifact, isPuppeteerAvailable,
|
|
12
|
+
* isMmdcAvailable, renderMermaidToPng, cleanupScreenshot }
|
|
13
|
+
* = require('./lib/screenshot-artifact.cjs');
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const os = require('os');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const cp = require('child_process');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check if puppeteer is available without throwing.
|
|
23
|
+
* @returns {boolean}
|
|
24
|
+
*/
|
|
25
|
+
function isPuppeteerAvailable() {
|
|
26
|
+
try { require.resolve('puppeteer'); return true; } catch { return false; }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Screenshot an HTML file to a temporary PNG using puppeteer (headless Chrome).
|
|
31
|
+
* Returns null silently when puppeteer is not installed.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} htmlPath - Absolute path to the HTML file to screenshot
|
|
34
|
+
* @param {object} [opts]
|
|
35
|
+
* @param {number} [opts.width=1280] - Viewport width in px
|
|
36
|
+
* @param {number} [opts.height=720] - Viewport height in px (matches 16:9 slide ratio)
|
|
37
|
+
* @returns {Promise<string|null>} Absolute path to a temp PNG file, or null if unavailable
|
|
38
|
+
*/
|
|
39
|
+
async function screenshotArtifact(htmlPath, opts = {}) {
|
|
40
|
+
// Graceful: return null if puppeteer not installed
|
|
41
|
+
let puppeteer;
|
|
42
|
+
try { puppeteer = require('puppeteer'); } catch { return null; }
|
|
43
|
+
|
|
44
|
+
if (!htmlPath || !fs.existsSync(htmlPath)) return null;
|
|
45
|
+
|
|
46
|
+
const { width = 1280, height = 720 } = opts;
|
|
47
|
+
const tmpFile = path.join(os.tmpdir(), `vp-artifact-${Date.now()}.png`);
|
|
48
|
+
|
|
49
|
+
const browser = await puppeteer.launch({
|
|
50
|
+
headless: 'new', // puppeteer ≥ 20 compat
|
|
51
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox'], // CI-safe
|
|
52
|
+
});
|
|
53
|
+
try {
|
|
54
|
+
const page = await browser.newPage();
|
|
55
|
+
await page.setViewport({ width, height });
|
|
56
|
+
await page.goto(`file://${htmlPath}`, { waitUntil: 'networkidle0', timeout: 15000 });
|
|
57
|
+
await page.screenshot({ path: tmpFile, fullPage: false });
|
|
58
|
+
return tmpFile;
|
|
59
|
+
} finally {
|
|
60
|
+
await browser.close();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Clean up a temp screenshot file after embedding.
|
|
66
|
+
* @param {string|null} tmpPath
|
|
67
|
+
*/
|
|
68
|
+
function cleanupScreenshot(tmpPath) {
|
|
69
|
+
if (tmpPath && fs.existsSync(tmpPath)) {
|
|
70
|
+
try { fs.unlinkSync(tmpPath); } catch { /* ignore cleanup errors */ }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ── Mermaid rendering (ENH-043) ───────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check if @mermaid-js/mermaid-cli (mmdc) is available on PATH.
|
|
78
|
+
* @returns {boolean}
|
|
79
|
+
*/
|
|
80
|
+
function isMmdcAvailable() {
|
|
81
|
+
try {
|
|
82
|
+
const r = cp.spawnSync('mmdc', ['--version'], { encoding: 'utf8', timeout: 5000 });
|
|
83
|
+
return r.status === 0;
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Render a Mermaid diagram source string to a PNG file using the mmdc CLI.
|
|
91
|
+
* Returns null silently when mmdc is not available or rendering fails.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} mermaidSource - Valid Mermaid 10+ source code
|
|
94
|
+
* @param {string} outputPath - Absolute path for the output .png file
|
|
95
|
+
* @returns {string|null} outputPath on success, null if mmdc absent or error
|
|
96
|
+
*/
|
|
97
|
+
function renderMermaidToPng(mermaidSource, outputPath) {
|
|
98
|
+
if (!isMmdcAvailable()) return null;
|
|
99
|
+
if (!mermaidSource || !mermaidSource.trim()) return null;
|
|
100
|
+
if (!outputPath) return null;
|
|
101
|
+
|
|
102
|
+
const tmpInput = outputPath.replace(/\.png$/i, '.mmd');
|
|
103
|
+
try {
|
|
104
|
+
fs.writeFileSync(tmpInput, mermaidSource, 'utf8');
|
|
105
|
+
const r = cp.spawnSync(
|
|
106
|
+
'mmdc',
|
|
107
|
+
['-i', tmpInput, '-o', outputPath, '-b', 'white'],
|
|
108
|
+
{ encoding: 'utf8', timeout: 30000 }
|
|
109
|
+
);
|
|
110
|
+
return (r.status === 0 && fs.existsSync(outputPath)) ? outputPath : null;
|
|
111
|
+
} catch {
|
|
112
|
+
return null;
|
|
113
|
+
} finally {
|
|
114
|
+
try { if (fs.existsSync(tmpInput)) fs.unlinkSync(tmpInput); } catch { /* ignore */ }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── Missing-tool warning (ENH-044) ───────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Emit a standardized warning to stderr when a visual rendering tool is absent
|
|
122
|
+
* but visual artifacts exist and embedding is mandatory.
|
|
123
|
+
*
|
|
124
|
+
* @param {string} tool - Tool name (e.g. 'puppeteer', 'mmdc')
|
|
125
|
+
* @param {string} installCmd - Install hint (e.g. 'npm install puppeteer')
|
|
126
|
+
*/
|
|
127
|
+
function warnMissingTool(tool, installCmd) {
|
|
128
|
+
process.stderr.write(
|
|
129
|
+
`\n[vp-proposal] ⚠ Visual artifacts found but '${tool}' is not installed.\n` +
|
|
130
|
+
` Install to enable screenshots: ${installCmd}\n` +
|
|
131
|
+
` Using placeholder/text fallback instead.\n\n`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = {
|
|
136
|
+
screenshotArtifact,
|
|
137
|
+
isPuppeteerAvailable,
|
|
138
|
+
cleanupScreenshot,
|
|
139
|
+
isMmdcAvailable,
|
|
140
|
+
renderMermaidToPng,
|
|
141
|
+
warnMissingTool,
|
|
142
|
+
};
|
package/lib/viepilot-config.cjs
CHANGED
|
@@ -13,12 +13,16 @@ const fs = require('fs');
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const os = require('os');
|
|
15
15
|
|
|
16
|
-
/** @type {{ language: { communication: string, document: string } }} */
|
|
16
|
+
/** @type {{ language: { communication: string, document: string }, proposal: { recentLangs: string[], defaultLang: string } }} */
|
|
17
17
|
const DEFAULTS = {
|
|
18
18
|
language: {
|
|
19
19
|
communication: 'en',
|
|
20
20
|
document: 'en',
|
|
21
21
|
},
|
|
22
|
+
proposal: {
|
|
23
|
+
recentLangs: [], // MRU list, most recent first, max 5
|
|
24
|
+
defaultLang: 'en', // kept in sync with recentLangs[0]
|
|
25
|
+
},
|
|
22
26
|
};
|
|
23
27
|
|
|
24
28
|
/**
|
|
@@ -94,10 +98,37 @@ function resetConfig(overrideHomedir) {
|
|
|
94
98
|
fs.writeFileSync(configPath, JSON.stringify(DEFAULTS, null, 2) + '\n', 'utf8');
|
|
95
99
|
}
|
|
96
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Get the suggested default language for proposals.
|
|
103
|
+
* Returns recentLangs[0] if present, else 'en'.
|
|
104
|
+
* @param {string | undefined} overrideHomedir
|
|
105
|
+
* @returns {string}
|
|
106
|
+
*/
|
|
107
|
+
function getProposalLang(overrideHomedir) {
|
|
108
|
+
const cfg = readConfig(overrideHomedir);
|
|
109
|
+
const recent = cfg.proposal && cfg.proposal.recentLangs;
|
|
110
|
+
return (Array.isArray(recent) && recent.length > 0) ? recent[0] : 'en';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Record a used language: prepend to recentLangs, dedup, cap at 5, sync defaultLang.
|
|
115
|
+
* @param {string} lang - ISO 639-1 code
|
|
116
|
+
* @param {string | undefined} overrideHomedir
|
|
117
|
+
*/
|
|
118
|
+
function recordProposalLang(lang, overrideHomedir) {
|
|
119
|
+
const cfg = readConfig(overrideHomedir);
|
|
120
|
+
const existing = (cfg.proposal && Array.isArray(cfg.proposal.recentLangs))
|
|
121
|
+
? cfg.proposal.recentLangs : [];
|
|
122
|
+
const updated = [lang, ...existing.filter(l => l !== lang)].slice(0, 5);
|
|
123
|
+
writeConfig({ proposal: { recentLangs: updated, defaultLang: updated[0] } }, overrideHomedir);
|
|
124
|
+
}
|
|
125
|
+
|
|
97
126
|
module.exports = {
|
|
98
127
|
DEFAULTS,
|
|
99
128
|
getConfigPath,
|
|
100
129
|
readConfig,
|
|
101
130
|
writeConfig,
|
|
102
131
|
resetConfig,
|
|
132
|
+
getProposalLang,
|
|
133
|
+
recordProposalLang,
|
|
103
134
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viepilot",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.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": {
|
|
@@ -72,6 +72,13 @@
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"docx": "^9.0.0",
|
|
77
|
+
"pptxgenjs": "^3.12.0"
|
|
78
|
+
},
|
|
79
|
+
"optionalDependencies": {
|
|
80
|
+
"@googleapis/slides": "^1.0.0"
|
|
81
|
+
},
|
|
75
82
|
"devDependencies": {
|
|
76
83
|
"jest": "^30.3.0"
|
|
77
84
|
}
|
package/skills/vp-audit/SKILL.md
CHANGED
|
@@ -34,6 +34,17 @@ Audit ViePilot project state and documentation to detect drift.
|
|
|
34
34
|
Works on **any project** using ViePilot (Java, Node, Python, etc.).
|
|
35
35
|
Auto-detects if running inside the viepilot framework repo to enable framework-specific checks.
|
|
36
36
|
|
|
37
|
+
**Brownfield Import Compatibility (FEAT-018):**
|
|
38
|
+
|
|
39
|
+
When auditing a project bootstrapped via `vp-crystallize --brownfield`:
|
|
40
|
+
|
|
41
|
+
- If `docs/brainstorm/` exists and contains **only** `session-brownfield-import.md` (no `session-*.md` greenfield files):
|
|
42
|
+
- **Valid brownfield import** — do NOT flag as missing brainstorm session.
|
|
43
|
+
- Verify `session-brownfield-import.md` contains a `## Scan Report` section with a YAML block.
|
|
44
|
+
- If YAML block absent → flag LOW severity: "Brownfield stub missing Scan Report content."
|
|
45
|
+
- If `.viepilot/TRACKER.md` contains `## Brownfield Import` section → brownfield metadata confirmed; no further brainstorm check needed.
|
|
46
|
+
- If `docs/brainstorm/` is completely absent → flag MEDIUM severity: "No brainstorm session or brownfield stub found — run `/vp-crystallize` or `/vp-crystallize --brownfield`."
|
|
47
|
+
|
|
37
48
|
**Tier 1 — ViePilot State Consistency (all projects):**
|
|
38
49
|
- `.viepilot/TRACKER.md` current state vs `.viepilot/phases/*/PHASE-STATE.md`
|
|
39
50
|
- `.viepilot/ROADMAP.md` phase status vs PHASE-STATE.md
|
|
@@ -107,3 +107,24 @@ Key steps:
|
|
|
107
107
|
- [ ] **FEAT-009**: intake completed, binding already present, **or** waiver with reason before Completed; session records **`## Project meta intake (FEAT-009)`**
|
|
108
108
|
- [ ] Next steps suggested
|
|
109
109
|
</success_criteria>
|
|
110
|
+
|
|
111
|
+
## Adapter Compatibility
|
|
112
|
+
|
|
113
|
+
### AskUserQuestion Tool (ENH-048)
|
|
114
|
+
This skill uses adapter-aware interactive prompts. Behavior depends on your adapter:
|
|
115
|
+
|
|
116
|
+
| Adapter | Interactive Prompts | Notes |
|
|
117
|
+
|---------|---------------------|-------|
|
|
118
|
+
| Claude Code (terminal) | ✅ `AskUserQuestion` tool | Click-to-select UI, multi-select, preview panels |
|
|
119
|
+
| Claude Code (VS Code ext) | ⚠️ Partial | Terminal yes; VS Code UI pending [anthropics/claude-code#12609](https://github.com/anthropics/claude-code/issues/12609) |
|
|
120
|
+
| Cursor (Plan Mode) | ⚠️ Partial | `AskQuestion` in Plan Mode only — not in Agent/Skills Mode |
|
|
121
|
+
| Cursor (Agent/Skills) | ❌ Text fallback | AskQuestion not available in Agent Mode |
|
|
122
|
+
| Codex CLI | ❌ Text fallback | Native tool N/A; community MCP available |
|
|
123
|
+
| Antigravity (native agent) | ❌ Text fallback | Artifact model, no raw tool calls |
|
|
124
|
+
|
|
125
|
+
When `AskUserQuestion` is not available, the skill automatically falls back to
|
|
126
|
+
plain-text numbered list prompts — no configuration required.
|
|
127
|
+
|
|
128
|
+
**Prompts using AskUserQuestion in this skill:**
|
|
129
|
+
- Session intent (continue / review / new — Step 2)
|
|
130
|
+
- Landing page layout selection (Step 4 — Layout A/B/C/D)
|
|
@@ -77,6 +77,46 @@ Convert brainstorm sessions into structured artifacts for autonomous AI executio
|
|
|
77
77
|
- `DOCUMENT_LANG` controls content language for all generated files (ROADMAP, TRACKER, ARCHITECTURE, etc.).
|
|
78
78
|
- `COMMUNICATION_LANG` controls prompt/confirmation language for this session.
|
|
79
79
|
- Configure via: `vp-tools config set language.document vi`
|
|
80
|
+
|
|
81
|
+
**Brownfield Mode (`--brownfield`) — FEAT-018:**
|
|
82
|
+
|
|
83
|
+
Use when adopting ViePilot on an **existing project** (no brainstorm session required).
|
|
84
|
+
|
|
85
|
+
Flags:
|
|
86
|
+
- `--brownfield` : Explicit brownfield mode
|
|
87
|
+
- *(auto-detected)* : Triggers when `docs/brainstorm/` is absent/empty AND `.viepilot/` does not exist
|
|
88
|
+
|
|
89
|
+
Scanner runs 12 signal categories across the existing codebase:
|
|
90
|
+
1. **Build manifests** — `package.json`, `pom.xml`, `pyproject.toml`, `Cargo.toml`, `go.mod`, etc. (11 platforms) → infers project_name, version, language, deps
|
|
91
|
+
2. **Framework detection** — 40+ dependency patterns → backend/frontend/ORM/auth/broker/test frameworks
|
|
92
|
+
3. **Architecture layers** — 18 directory patterns → controller/service/repository/frontend/infra/etc.
|
|
93
|
+
4. **Database schema signals** — Flyway/Liquibase/Prisma/Rails migrations + docker-compose services
|
|
94
|
+
5. **API contracts** — OpenAPI, gRPC `.proto`, GraphQL schemas
|
|
95
|
+
6. **Infrastructure** — Dockerfile, docker-compose, k8s, Terraform, Vercel, Fly.io, etc. (16 patterns)
|
|
96
|
+
7. **Environment config** — `.env.example` key names (never reads `.env`)
|
|
97
|
+
8. **Test coverage** — Jest/pytest/JUnit/Cypress config + coverage report dirs
|
|
98
|
+
9. **Code quality tools** — ESLint/Prettier/SonarQube/pre-commit/golangci-lint/etc. (14 patterns)
|
|
99
|
+
10. **Documentation** — README, CHANGELOG, ADRs, docs/ (priority-ordered)
|
|
100
|
+
11. **Git history** — commit convention, version pattern, contributors, repo URL
|
|
101
|
+
12. **Language survey** — file extension glob → language distribution
|
|
102
|
+
|
|
103
|
+
**Multi-repo / monorepo support (ENH-047):**
|
|
104
|
+
|
|
105
|
+
- **Git submodule detection** — reads `.gitmodules`; scans each initialized submodule path (Signal Cat 1+2+4); records uninitialized paths as `primary_language: MISSING`. Never runs `git submodule update` — read-only.
|
|
106
|
+
- **Polyrepo hints** — detects docker-compose `../` build contexts, `file:../` deps, CI cross-repo clones, README external links, Makefile `cd ../` targets; outputs `polyrepo_hints[]`; prompts user to supply `related_repos[]` (optional).
|
|
107
|
+
- **Per-module gap detection** — every `modules[]` entry carries `gap_tier` (DETECTED/ASSUMED/MISSING), `must_detect_status{}` (evidence per field: value + source + tier), and `open_questions[]`. A module with `gap_tier: MISSING` blocks artifact generation with a targeted per-field prompt.
|
|
108
|
+
|
|
109
|
+
**Scan Report contains:**
|
|
110
|
+
- Root `gap_tier` (= worst tier across all modules: MISSING > ASSUMED > DETECTED)
|
|
111
|
+
- `modules[]` — one entry per workspace/submodule/root with `gap_tier`, `must_detect_status{}`, `open_questions[]`
|
|
112
|
+
- `polyrepo_hints[]` — polyrepo signals (omitted when empty, no empty arrays)
|
|
113
|
+
- `related_repos[]` — user-supplied sibling repos (omitted when empty)
|
|
114
|
+
- Root `open_questions[]` — includes rollup from all modules
|
|
115
|
+
|
|
116
|
+
Produces **Scan Report** (YAML) with DETECTED / ASSUMED / MISSING classification.
|
|
117
|
+
MUST-DETECT gaps (root: project_name, primary_language, ≥1 framework, current_version; per-module: primary_language, framework, module_purpose, entry_point) block artifact generation until user fills interactively.
|
|
118
|
+
Generates `docs/brainstorm/session-brownfield-import.md` stub for `vp-audit` compatibility.
|
|
119
|
+
Safety: never reads `.env`; skips `node_modules/`, `.git/`, `target/`, `build/`, `dist/`.
|
|
80
120
|
</objective>
|
|
81
121
|
|
|
82
122
|
<execution_context>
|
|
@@ -223,3 +263,27 @@ Ask user for (confirm proposals from profile if present):
|
|
|
223
263
|
- [ ] **ENH-022:** Every generated Mermaid diagram has a `.viepilot/architecture/<canonical-name>.mermaid` file in sync with `ARCHITECTURE.md` (no extra files created for N/A)
|
|
224
264
|
- [ ] **FEAT-009:** When profile is bound — ARCHITECTURE + PROJECT-CONTEXT record the profile source; if not — state none / not configured explicitly
|
|
225
265
|
</success_criteria>
|
|
266
|
+
|
|
267
|
+
## Adapter Compatibility
|
|
268
|
+
|
|
269
|
+
### AskUserQuestion Tool (ENH-048)
|
|
270
|
+
This skill uses adapter-aware interactive prompts. Behavior depends on your adapter:
|
|
271
|
+
|
|
272
|
+
| Adapter | Interactive Prompts | Notes |
|
|
273
|
+
|---------|---------------------|-------|
|
|
274
|
+
| Claude Code (terminal) | ✅ `AskUserQuestion` tool | Click-to-select UI, multi-select, preview panels |
|
|
275
|
+
| Claude Code (VS Code ext) | ⚠️ Partial | Terminal yes; VS Code UI pending [anthropics/claude-code#12609](https://github.com/anthropics/claude-code/issues/12609) |
|
|
276
|
+
| Cursor (Plan Mode) | ⚠️ Partial | `AskQuestion` in Plan Mode only — not in Agent/Skills Mode |
|
|
277
|
+
| Cursor (Agent/Skills) | ❌ Text fallback | AskQuestion not available in Agent Mode |
|
|
278
|
+
| Codex CLI | ❌ Text fallback | Native tool N/A; community MCP available |
|
|
279
|
+
| Antigravity (native agent) | ❌ Text fallback | Artifact model, no raw tool calls |
|
|
280
|
+
|
|
281
|
+
When `AskUserQuestion` is not available, the skill automatically falls back to
|
|
282
|
+
plain-text numbered list prompts — no configuration required.
|
|
283
|
+
|
|
284
|
+
**Prompts using AskUserQuestion in this skill:**
|
|
285
|
+
- License selection (Step 0 metadata)
|
|
286
|
+
- Brownfield overwrite confirmation (Step 0-B)
|
|
287
|
+
- Polyrepo related-repos prompt (Step 0-B)
|
|
288
|
+
- UI direction gate choice (Step 1A)
|
|
289
|
+
- Architect mode suggestion (Step 1D)
|
package/skills/vp-docs/SKILL.md
CHANGED
|
@@ -80,19 +80,29 @@ Optional flags:
|
|
|
80
80
|
|
|
81
81
|
### Step 0: Resolve Project Context (ALWAYS first)
|
|
82
82
|
```bash
|
|
83
|
-
#
|
|
83
|
+
# Forge-agnostic remote URL parser — supports GitHub, GitLab, Bitbucket, Azure DevOps, Gitea, self-hosted
|
|
84
84
|
REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
if echo "$REMOTE_URL" | grep -q 'dev\.azure\.com'; then
|
|
86
|
+
GIT_HOST="dev.azure.com"
|
|
87
|
+
GIT_OWNER=$(echo "$REMOTE_URL" | sed 's|.*dev\.azure\.com/||; s|/.*||')
|
|
88
|
+
GIT_REPO=$(echo "$REMOTE_URL" | sed 's|.*/_git/||; s|\.git$||; s|/$||')
|
|
89
|
+
elif echo "$REMOTE_URL" | grep -q '^git@'; then
|
|
90
|
+
GIT_HOST=$(echo "$REMOTE_URL" | sed 's|^git@||; s|:.*||')
|
|
91
|
+
GIT_OWNER=$(echo "$REMOTE_URL" | sed 's|^git@[^:]*:||; s|/.*||')
|
|
92
|
+
GIT_REPO=$(echo "$REMOTE_URL" | sed 's|^git@[^:]*:[^/]*/||; s|\.git$||')
|
|
93
|
+
else
|
|
94
|
+
GIT_HOST=$(echo "$REMOTE_URL" | sed 's|^https\?://||; s|/.*||')
|
|
95
|
+
GIT_OWNER=$(echo "$REMOTE_URL" | sed 's|^https\?://[^/]*/||; s|/.*||')
|
|
96
|
+
GIT_REPO=$(echo "$REMOTE_URL" | sed 's|^https\?://[^/]*/[^/]*/||; s|\.git$||; s|/$||')
|
|
97
|
+
fi
|
|
88
98
|
# Fallback: use searchable placeholder, not 'your-org'
|
|
89
|
-
[ -z "$
|
|
99
|
+
[ -z "$GIT_OWNER" ] && GIT_HOST="{GIT_HOST}" && GIT_OWNER="{GIT_OWNER}" && GIT_REPO="{GIT_REPO}"
|
|
90
100
|
|
|
91
101
|
ACTUAL_SKILLS=$(ls skills/*/SKILL.md 2>/dev/null | wc -l | tr -d ' ')
|
|
92
102
|
ACTUAL_WORKFLOWS=$(ls workflows/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
93
103
|
```
|
|
94
104
|
|
|
95
|
-
> Use `$
|
|
105
|
+
> Use `$GIT_HOST`, `$GIT_OWNER`, `$GIT_REPO` in all generated files.
|
|
96
106
|
> Use `$ACTUAL_SKILLS` and `$ACTUAL_WORKFLOWS` for counts.
|
|
97
107
|
> **Never write** `your-org`, `YOUR_USERNAME`, `YOUR_ORG` into generated files.
|
|
98
108
|
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vp-proposal
|
|
3
|
+
description: "Generate professional proposal packages (.pptx + .docx + .md) from brainstorm sessions or direct briefs"
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<cursor_skill_adapter>
|
|
8
|
+
## A. Skill Invocation
|
|
9
|
+
- Skill được gọi khi user mention `vp-proposal`, `/vp-proposal`, "proposal", "pitch deck", "presentation", "tài liệu đề xuất"
|
|
10
|
+
- Treat all user text after the skill mention as `{{VP_ARGS}}`
|
|
11
|
+
|
|
12
|
+
## B. User Prompting
|
|
13
|
+
Prompt user conversationally with numbered list options.
|
|
14
|
+
|
|
15
|
+
## C. Tool Usage
|
|
16
|
+
Use Cursor tools: `Shell`, `ReadFile`, `Glob`, `rg`, `ApplyPatch`, `WebSearch`, `WebFetch`, `Subagent`
|
|
17
|
+
</cursor_skill_adapter>
|
|
18
|
+
<scope_policy>
|
|
19
|
+
## ViePilot Namespace Guard (BUG-004)
|
|
20
|
+
- Default mode: only use and reference `vp-*` skills in ViePilot workflows.
|
|
21
|
+
- External skills (`non vp-*`) are out of framework scope unless user explicitly opts in.
|
|
22
|
+
</scope_policy>
|
|
23
|
+
<implementation_routing_guard>
|
|
24
|
+
## Implementation routing guard (ENH-021)
|
|
25
|
+
|
|
26
|
+
- **`/vp-proposal`** generates **output artifacts** (`docs/proposals/*.pptx`, `*.docx`, `*.md`) — it does **not** implement shipping code for `lib/`, `tests/`, `bin/`, or framework `workflows/`/`skills/`.
|
|
27
|
+
- This skill is the **delivery lane** after `/vp-brainstorm` captures the ideas. Use `/vp-request` → `/vp-evolve` → `/vp-auto` for ViePilot framework feature work.
|
|
28
|
+
- **Exception:** User **explicit** bypass — state clearly in chat.
|
|
29
|
+
</implementation_routing_guard>
|
|
30
|
+
|
|
31
|
+
<objective>
|
|
32
|
+
Generate a professional proposal package from a brainstorm session or direct brief.
|
|
33
|
+
|
|
34
|
+
**Output files** (written to `docs/proposals/`):
|
|
35
|
+
- `{slug}-{date}.md` — structured proposal Markdown (source of truth)
|
|
36
|
+
- `{slug}-{date}.pptx` — presentation file (ViePilot branded, dark navy/charcoal)
|
|
37
|
+
- `{slug}-{date}.docx` — detailed project document
|
|
38
|
+
- `{slug}-{date}-slides.txt` — Google Slides URL (only with `--slides` flag)
|
|
39
|
+
|
|
40
|
+
**Proposal types:**
|
|
41
|
+
| Type | Slides | Use case |
|
|
42
|
+
|------|--------|----------|
|
|
43
|
+
| `project-proposal` | 10 | Scope, timeline, budget for clients |
|
|
44
|
+
| `tech-architecture` | 12 | Technical design for partners |
|
|
45
|
+
| `product-pitch` | 12 | Investor / partner pitch deck |
|
|
46
|
+
| `general` | 8 | Generic, fallback |
|
|
47
|
+
|
|
48
|
+
**Template resolution (2-tier):**
|
|
49
|
+
1. `.viepilot/proposal-templates/{type}.pptx` — project-level override
|
|
50
|
+
2. `{viepilot-install}/templates/proposal/pptx/{type}.pptx` — ViePilot stock
|
|
51
|
+
|
|
52
|
+
**Context detection:**
|
|
53
|
+
- Auto-loads latest `docs/brainstorm/session-*.md` when present
|
|
54
|
+
- Standalone mode if no session found (user provides brief)
|
|
55
|
+
- `--from session-YYYY-MM-DD.md` for explicit session selection
|
|
56
|
+
</objective>
|
|
57
|
+
|
|
58
|
+
<execution_context>
|
|
59
|
+
workflows/proposal.md
|
|
60
|
+
</execution_context>
|
|
61
|
+
|
|
62
|
+
<context>
|
|
63
|
+
Optional flags:
|
|
64
|
+
- `--type <id>` : Proposal type — `project-proposal` | `tech-architecture` | `product-pitch` | `general`
|
|
65
|
+
If omitted: guided selection menu is shown
|
|
66
|
+
- `--from <file>` : Explicit brainstorm session file to use as context
|
|
67
|
+
Default: auto-detect latest `docs/brainstorm/session-*.md`
|
|
68
|
+
- `--lang <code>` : Language for generated content — ISO 639-1 (e.g. vi, en, ja, fr, zh).
|
|
69
|
+
If omitted: prompted with MRU suggestions from config.
|
|
70
|
+
Saved to ~/.viepilot/config.json → proposal.recentLangs after generation.
|
|
71
|
+
- `--lang-content-only` : Translate content (bullets, notes, paragraphs) only.
|
|
72
|
+
Keep structural labels / section names in English.
|
|
73
|
+
- `--slides` : After .pptx is generated, upload to Google Slides via service account auth
|
|
74
|
+
Requires: `@googleapis/slides` installed + `GOOGLE_APPLICATION_CREDENTIALS` env var
|
|
75
|
+
- `--dry-run` : Show slide manifest (JSON) without writing any files
|
|
76
|
+
</context>
|
|
77
|
+
|
|
78
|
+
<process>
|
|
79
|
+
Execute workflow from `workflows/proposal.md`
|
|
80
|
+
|
|
81
|
+
### Step 1: Context Detection
|
|
82
|
+
- Scan `docs/brainstorm/` for `session-*.md` → sort descending → load latest
|
|
83
|
+
- If `--from` specified: load that file directly
|
|
84
|
+
- If no session found: prompt user for brief:
|
|
85
|
+
- Project name
|
|
86
|
+
- One-line description
|
|
87
|
+
- Target audience (client / partner / investor)
|
|
88
|
+
- 3–5 key points to cover
|
|
89
|
+
|
|
90
|
+
### Step 2: Proposal Type Selection
|
|
91
|
+
- If `--type` provided: validate; show type + slide count to confirm
|
|
92
|
+
- Else: present menu:
|
|
93
|
+
```
|
|
94
|
+
1. Project Proposal (10 slides) — scope, timeline, budget
|
|
95
|
+
2. Tech Architecture (12 slides) — system design for partners
|
|
96
|
+
3. Product Pitch Deck (12 slides) — investor / partner pitch
|
|
97
|
+
4. General Proposal ( 8 slides) — generic fallback
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Step 3: AI Slide Manifest Generation
|
|
101
|
+
- Structure context into JSON manifest:
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"title": "...",
|
|
105
|
+
"subtitle": "...",
|
|
106
|
+
"slides": [
|
|
107
|
+
{ "index": 1, "layout": "cover", "heading": "...", "body": "...", "speakerNotes": "..." },
|
|
108
|
+
{ "index": 2, "layout": "section", "heading": "...", "bullets": ["..."], "speakerNotes": "..." }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
- Slide count MUST match `PROPOSAL_TYPES[typeId].slides`
|
|
113
|
+
- If `--dry-run`: print manifest and stop
|
|
114
|
+
|
|
115
|
+
### Step 4: Template Resolution
|
|
116
|
+
- Call `resolveTemplate(typeId, 'pptx', projectRoot)` → pptx template path
|
|
117
|
+
- Call `resolveTemplate('project-detail', 'docx', projectRoot)` → docx template path
|
|
118
|
+
- Warn (not error) if stock fallback is used
|
|
119
|
+
|
|
120
|
+
### Step 5: Generate .pptx
|
|
121
|
+
- Load template via pptxgenjs
|
|
122
|
+
- Apply slide manifest: inject titles, bullets, speaker notes per slide
|
|
123
|
+
- Ensure `docs/proposals/` directory exists
|
|
124
|
+
- Write `{slug}-{date}.pptx`
|
|
125
|
+
|
|
126
|
+
### Step 6: Generate .docx
|
|
127
|
+
- Build detailed document from same manifest + extended content
|
|
128
|
+
- Sections: Executive Summary, Problem & Solution, Features & Specifications,
|
|
129
|
+
Technical Architecture (if relevant), Timeline, Team, Appendix
|
|
130
|
+
- Write `{slug}-{date}.docx`
|
|
131
|
+
|
|
132
|
+
### Step 7: Generate .md summary
|
|
133
|
+
- Write Markdown mirror of the manifest
|
|
134
|
+
- Save `{slug}-{date}.md`
|
|
135
|
+
|
|
136
|
+
### Step 8: Optional Google Slides upload (`--slides`)
|
|
137
|
+
- Call `lib/google-slides-exporter.cjs` → `uploadToSlides(pptxPath, title)`
|
|
138
|
+
- Write URL to `{slug}-{date}-slides.txt`
|
|
139
|
+
- On failure: surface error but do NOT fail the whole command (files already written)
|
|
140
|
+
|
|
141
|
+
### Step 9: Confirm output
|
|
142
|
+
```
|
|
143
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
144
|
+
VIEPILOT ► PROPOSAL GENERATED ✓
|
|
145
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
146
|
+
Type: {type label} ({N} slides)
|
|
147
|
+
Context: {session file or "direct brief"}
|
|
148
|
+
|
|
149
|
+
Files:
|
|
150
|
+
docs/proposals/{slug}-{date}.md
|
|
151
|
+
docs/proposals/{slug}-{date}.pptx
|
|
152
|
+
docs/proposals/{slug}-{date}.docx
|
|
153
|
+
[docs/proposals/{slug}-{date}-slides.txt] ← if --slides
|
|
154
|
+
|
|
155
|
+
Next:
|
|
156
|
+
Open .pptx in PowerPoint / Keynote / LibreOffice
|
|
157
|
+
Share .docx as supporting document
|
|
158
|
+
Run /vp-proposal --slides to upload to Google Slides
|
|
159
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
160
|
+
```
|
|
161
|
+
</process>
|
|
162
|
+
|
|
163
|
+
<success_criteria>
|
|
164
|
+
- [ ] Context detected (brainstorm session or user brief)
|
|
165
|
+
- [ ] Proposal type selected and validated
|
|
166
|
+
- [ ] Slide manifest generated with correct slide count
|
|
167
|
+
- [ ] .pptx written to docs/proposals/
|
|
168
|
+
- [ ] .docx written to docs/proposals/
|
|
169
|
+
- [ ] .md summary written to docs/proposals/
|
|
170
|
+
- [ ] Template resolution: project override takes precedence over stock
|
|
171
|
+
- [ ] --lang: content generated in specified language; MRU saved to config
|
|
172
|
+
- [ ] --lang-content-only: bullets/notes translated; structural labels stay English
|
|
173
|
+
- [ ] --slides: Google Slides URL written to -slides.txt (or clear error shown)
|
|
174
|
+
- [ ] --dry-run: manifest printed, no files written
|
|
175
|
+
</success_criteria>
|
|
@@ -265,3 +265,25 @@ Update `.viepilot/TRACKER.md`:
|
|
|
265
265
|
- [ ] TRACKER.md updated
|
|
266
266
|
- [ ] Appropriate routing suggested
|
|
267
267
|
</success_criteria>
|
|
268
|
+
|
|
269
|
+
## Adapter Compatibility
|
|
270
|
+
|
|
271
|
+
### AskUserQuestion Tool (ENH-048)
|
|
272
|
+
This skill uses adapter-aware interactive prompts. Behavior depends on your adapter:
|
|
273
|
+
|
|
274
|
+
| Adapter | Interactive Prompts | Notes |
|
|
275
|
+
|---------|---------------------|-------|
|
|
276
|
+
| Claude Code (terminal) | ✅ `AskUserQuestion` tool | Click-to-select UI, multi-select, preview panels |
|
|
277
|
+
| Claude Code (VS Code ext) | ⚠️ Partial | Terminal yes; VS Code UI pending [anthropics/claude-code#12609](https://github.com/anthropics/claude-code/issues/12609) |
|
|
278
|
+
| Cursor (Plan Mode) | ⚠️ Partial | `AskQuestion` in Plan Mode only — not in Agent/Skills Mode |
|
|
279
|
+
| Cursor (Agent/Skills) | ❌ Text fallback | AskQuestion not available in Agent Mode |
|
|
280
|
+
| Codex CLI | ❌ Text fallback | Native tool N/A; community MCP available |
|
|
281
|
+
| Antigravity (native agent) | ❌ Text fallback | Artifact model, no raw tool calls |
|
|
282
|
+
|
|
283
|
+
When `AskUserQuestion` is not available, the skill automatically falls back to
|
|
284
|
+
plain-text numbered list prompts — no configuration required.
|
|
285
|
+
|
|
286
|
+
**Prompts using AskUserQuestion in this skill:**
|
|
287
|
+
- Request type detection (Bug / Feature / Enhancement / Tech Debt — Step 2)
|
|
288
|
+
- Bug severity selection (Critical / High / Medium / Low — Step 4A)
|
|
289
|
+
- Feature priority selection (Must-have / Should-have / Nice-to-have — Step 4B)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/workflows/brainstorm.md
CHANGED
|
@@ -3,6 +3,14 @@ Interactive brainstorm session to gather ideas, requirements, and decisions for
|
|
|
3
3
|
Allows research inline within the same brainstorm session when needed.
|
|
4
4
|
</purpose>
|
|
5
5
|
|
|
6
|
+
## Adapter Compatibility
|
|
7
|
+
|
|
8
|
+
| Feature | Claude Code (terminal) | Cursor (Agent/Skills) | Codex CLI | Antigravity (native) |
|
|
9
|
+
|---------|----------------------|-----------------------|-----------|----------------------|
|
|
10
|
+
| Interactive prompts | ✅ `AskUserQuestion` tool | ❌ text fallback | ❌ text fallback | ❌ text fallback |
|
|
11
|
+
|
|
12
|
+
When `AskUserQuestion` is not available, each prompt block falls back to the plain-text numbered list shown below it — no configuration needed.
|
|
13
|
+
|
|
6
14
|
## ViePilot Skill Scope Policy (BUG-004)
|
|
7
15
|
|
|
8
16
|
- Default behavior: only use and suggest skills under `vp-*`.
|
|
@@ -37,6 +45,15 @@ Parse results to get list of existing sessions.
|
|
|
37
45
|
## 2. Ask User Intent
|
|
38
46
|
|
|
39
47
|
**If previous sessions exist:**
|
|
48
|
+
|
|
49
|
+
> **Adapter-aware prompt:**
|
|
50
|
+
> - **Claude Code (terminal):** use `AskUserQuestion` tool — spec:
|
|
51
|
+
> - question: "Previous brainstorm sessions found. What would you like to do?"
|
|
52
|
+
> - header: "Session"
|
|
53
|
+
> - options: [{ label: "Continue recent session", description: "Resume the most recent session from where it stopped" }, { label: "Review specific session", description: "Choose a particular session to review or continue" }, { label: "New brainstorm session", description: "Start fresh — previous sessions are preserved" }]
|
|
54
|
+
> - multiSelect: false
|
|
55
|
+
> - **Cursor / Codex / Antigravity / other:** use text menu below
|
|
56
|
+
|
|
40
57
|
```
|
|
41
58
|
I found previous brainstorm sessions:
|
|
42
59
|
{list sessions with dates}
|
|
@@ -118,6 +135,15 @@ If the user is brainstorming a landing page / homepage / marketing page:
|
|
|
118
135
|
- Visual tone? (minimal, modern, bold, enterprise, playful)
|
|
119
136
|
- Primary CTA and secondary CTA?
|
|
120
137
|
2. Present a layout menu for the user to choose from:
|
|
138
|
+
|
|
139
|
+
> **Adapter-aware prompt:**
|
|
140
|
+
> - **Claude Code (terminal):** use `AskUserQuestion` tool — spec:
|
|
141
|
+
> - question: "Which landing page layout fits your goals and audience?"
|
|
142
|
+
> - header: "Layout"
|
|
143
|
+
> - options: [{ label: "Layout A — Hero centric", description: "Hero + trust logos + features + CTA — best for brand awareness and conversions" }, { label: "Layout B — Problem/Solution", description: "Problem/Solution + social proof + pricing + FAQ — best for SaaS sign-ups" }, { label: "Layout C — Product storytelling", description: "Screenshots + testimonials + final CTA — best for product demos" }, { label: "Layout D — SaaS conversion", description: "Integrations + comparison + onboarding steps — best for tool adoption" }]
|
|
144
|
+
> - multiSelect: false
|
|
145
|
+
> - **Cursor / Codex / Antigravity / other:** use list below
|
|
146
|
+
|
|
121
147
|
- Layout A: Hero centric + trust logos + features + CTA
|
|
122
148
|
- Layout B: Problem/Solution + social proof + pricing + FAQ
|
|
123
149
|
- Layout C: Product storytelling + screenshots + testimonials + final CTA
|