viepilot 2.50.1 → 3.7.3
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 +214 -0
- package/README.md +17 -17
- package/bin/viepilot.cjs +1 -0
- package/bin/vp-tools.cjs +123 -1
- package/docs/brainstorm/session-2026-05-22.md +472 -0
- package/docs/dev/agents.md +51 -41
- package/docs/dev/architecture.md +26 -0
- package/docs/skills-reference.md +96 -0
- package/lib/adapter-context.cjs +294 -0
- package/lib/adapters/antigravity.cjs +8 -2
- package/lib/adapters/claude-code.cjs +4 -0
- package/lib/audit/browser-runner.cjs +102 -0
- package/lib/intake/adapters/browser.cjs +58 -0
- package/lib/intake/adapters/excel-m365.cjs +54 -6
- package/lib/intake/auto-intake.cjs +194 -0
- package/lib/intake/classifier.cjs +22 -4
- package/lib/intake/manifest.cjs +81 -0
- package/lib/intake/triage-ux.cjs +10 -2
- package/lib/intake/validator.cjs +97 -0
- package/lib/intake/writeback.cjs +169 -3
- package/lib/request/url-enricher.cjs +69 -0
- package/lib/viepilot-install.cjs +15 -0
- package/package.json +1 -1
- package/skills/vp-audit/SKILL.md +99 -3
- package/skills/vp-auto/SKILL.md +54 -4
- package/skills/vp-brainstorm/SKILL.md +69 -3
- package/skills/vp-crystallize/SKILL.md +52 -3
- package/skills/vp-debug/SKILL.md +52 -3
- package/skills/vp-design/SKILL.md +52 -3
- package/skills/vp-docs/SKILL.md +52 -3
- package/skills/vp-evolve/SKILL.md +52 -3
- package/skills/vp-info/SKILL.md +52 -3
- package/skills/vp-intake/SKILL.md +306 -7
- package/skills/vp-pause/SKILL.md +52 -3
- package/skills/vp-persona/SKILL.md +52 -3
- package/skills/vp-proposal/SKILL.md +52 -3
- package/skills/vp-request/SKILL.md +72 -3
- package/skills/vp-resume/SKILL.md +52 -3
- package/skills/vp-rollback/SKILL.md +52 -3
- package/skills/vp-skills/SKILL.md +52 -3
- package/skills/vp-status/SKILL.md +52 -3
- package/skills/vp-task/SKILL.md +52 -3
- package/skills/vp-ui-components/SKILL.md +52 -3
- package/skills/vp-update/SKILL.md +52 -3
- package/workflows/autonomous.md +268 -18
- package/workflows/brainstorm.md +222 -7
- package/workflows/crystallize.md +124 -6
- package/workflows/design.md +62 -1
- package/workflows/request.md +54 -8
package/docs/skills-reference.md
CHANGED
|
@@ -547,3 +547,99 @@ Full guide: `docs/user/features/proposal.md`
|
|
|
547
547
|
- Fallback: `~/.cursor/viepilot/bin/vp-tools.cjs` for Cursor adapter.
|
|
548
548
|
- Registry file: `~/.viepilot/skill-registry.json` — shared across all projects.
|
|
549
549
|
- Confirmation AUQ prompt before destructive `uninstall` (Claude Code terminal only).
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
## /vp-design
|
|
554
|
+
|
|
555
|
+
Visual/UI direction skill. Generates UI architecture: component map, color system, typography,
|
|
556
|
+
responsive breakpoints, and Pencil design file integration.
|
|
557
|
+
|
|
558
|
+
### Triggers
|
|
559
|
+
`vp-design`, `/vp-design`, "thiết kế UI", "UI direction", "design system"
|
|
560
|
+
|
|
561
|
+
### Flags
|
|
562
|
+
- `--new` : Start fresh UI direction session
|
|
563
|
+
- `--component <name>` : Design a specific component
|
|
564
|
+
- `--mobile` : Mobile-first emphasis
|
|
565
|
+
- `--architect` : Generate Architect HTML view alongside
|
|
566
|
+
|
|
567
|
+
### Flow
|
|
568
|
+
1. Collect product goals + target audience + brand constraints
|
|
569
|
+
2. Generate UI direction: color palette, typography, spacing scale, component inventory
|
|
570
|
+
3. Output Pencil design stubs (if Pencil MCP available) or Architect HTML fallback
|
|
571
|
+
4. Write `docs/ui-direction.md` and `PROJECT-CONTEXT.md ## UI Direction`
|
|
572
|
+
|
|
573
|
+
### Output
|
|
574
|
+
- `docs/ui-direction.md` (created/updated)
|
|
575
|
+
- `PROJECT-CONTEXT.md` UI Direction section (locked by `/vp-crystallize` Step 1E)
|
|
576
|
+
- Optional: Pencil `.pen` file stubs via `mcp__pencil__batch_design`
|
|
577
|
+
|
|
578
|
+
### Adapter-Aware Prompts
|
|
579
|
+
Uses `AskUserQuestion` on Claude Code terminal for design-direction questions.
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
## /vp-intake
|
|
584
|
+
|
|
585
|
+
Structured intake from Google Sheets, Excel (M365), CSV files, and browser URLs. Reads rows
|
|
586
|
+
from a configured source, creates ViePilot request files, and optionally writes results back.
|
|
587
|
+
|
|
588
|
+
### Triggers
|
|
589
|
+
`vp-intake`, `/vp-intake`, "đọc intake", "intake từ sheet", "load requests from sheet"
|
|
590
|
+
|
|
591
|
+
### Flags
|
|
592
|
+
- `--channel <id>` : Force a specific intake channel (sheets/excel/csv/browser)
|
|
593
|
+
- `--dry-run` : Parse and triage without writing request files
|
|
594
|
+
- `--no-writeback` : Skip writing results back to source
|
|
595
|
+
- `--setup` : Launch AUQ-driven channel configuration wizard (ENH-084)
|
|
596
|
+
|
|
597
|
+
### Flow
|
|
598
|
+
1. Load intake manifest (`~/.viepilot/intake-manifests/<project>.json`) or prompt setup
|
|
599
|
+
2. Read rows from configured channel (Google Sheets via API, Excel via M365 Graph, CSV, or browser-agent for public URLs)
|
|
600
|
+
3. Triage each row: detect type (bug/feature/enhancement/debt), extract title/description
|
|
601
|
+
4. Create `.viepilot/requests/{TYPE}-{N}.md` for each valid row
|
|
602
|
+
5. Write-back status column to source row (if writable channel)
|
|
603
|
+
|
|
604
|
+
### Output
|
|
605
|
+
- `.viepilot/requests/{TYPE}-{N}.md` per intake row
|
|
606
|
+
- Intake manifest updated with last-read cursor
|
|
607
|
+
- Source row status updated (write-back, if enabled)
|
|
608
|
+
|
|
609
|
+
### Adapters
|
|
610
|
+
Full support: Claude Code. Partial: Cursor (no AUQ). Text fallback: Codex/Copilot/Antigravity.
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
## /vp-persona
|
|
615
|
+
|
|
616
|
+
Manages the global developer persona profile stored in `~/.viepilot/config.json`. Persona
|
|
617
|
+
controls output style, stack preferences, and team-size assumptions injected into every skill.
|
|
618
|
+
|
|
619
|
+
### Triggers
|
|
620
|
+
`vp-persona`, `/vp-persona`, "cấu hình persona", "set persona", "developer profile"
|
|
621
|
+
|
|
622
|
+
### Flags
|
|
623
|
+
- `--set` : Interactively set persona fields
|
|
624
|
+
- `--show` : Print current active persona
|
|
625
|
+
- `--auto-switch` : Switch persona based on current project stack (used internally by skills)
|
|
626
|
+
- `--context` : Print persona as `## User Persona` block (used by skill banners)
|
|
627
|
+
|
|
628
|
+
### Persona Fields
|
|
629
|
+
| Field | Values | Default |
|
|
630
|
+
|-------|--------|---------|
|
|
631
|
+
| `role` | backend / frontend / fullstack / devops / data / mobile | backend |
|
|
632
|
+
| `domain` | web-saas / mobile / api / data / infra / other | web-saas |
|
|
633
|
+
| `stacks` | comma-separated list | — |
|
|
634
|
+
| `outputStyle` | lean / verbose | lean |
|
|
635
|
+
| `phaseTemplate` | lean-startup / enterprise / research | lean-startup |
|
|
636
|
+
| `teamSize` | solo / small / medium / large | solo |
|
|
637
|
+
|
|
638
|
+
### Flow
|
|
639
|
+
1. `vp-tools persona auto-switch` — detects stack from package.json / pyproject.toml / build.gradle
|
|
640
|
+
2. `vp-tools persona context` — outputs `## User Persona` markdown block
|
|
641
|
+
3. Skills inject this block silently before task execution
|
|
642
|
+
|
|
643
|
+
### Output
|
|
644
|
+
- `~/.viepilot/config.json` updated
|
|
645
|
+
- `## User Persona` injected into each skill session
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ADAPTER_CONTEXT — per-adapter capability map for ViePilot v3.
|
|
5
|
+
*
|
|
6
|
+
* Each adapter entry defines:
|
|
7
|
+
* tools{} — canonical tool name for each abstract operation
|
|
8
|
+
* interactive — "AUQ" | "text" | "text-plan-only" | "none"
|
|
9
|
+
* orchestration{} — parallel dispatch capability
|
|
10
|
+
* hooks{} — hook event support
|
|
11
|
+
* mcp{} — MCP support constraints
|
|
12
|
+
* subagent — "multi-level" | "single-level" | "command-only" | "none"
|
|
13
|
+
*
|
|
14
|
+
* Skills read ADAPTER_CONTEXT instead of maintaining inline compat tables.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const ADAPTER_CONTEXTS = {
|
|
18
|
+
|
|
19
|
+
'claude-code': {
|
|
20
|
+
id: 'claude-code',
|
|
21
|
+
name: 'Claude Code',
|
|
22
|
+
tools: {
|
|
23
|
+
shell: 'Bash',
|
|
24
|
+
read: 'Read',
|
|
25
|
+
write: 'Write',
|
|
26
|
+
edit: 'Edit',
|
|
27
|
+
multi_edit: 'MultiEdit',
|
|
28
|
+
search: 'Grep',
|
|
29
|
+
glob: 'Glob',
|
|
30
|
+
ls: 'LS',
|
|
31
|
+
web_search: 'WebSearch',
|
|
32
|
+
web_fetch: 'WebFetch',
|
|
33
|
+
notebook_read: 'NotebookRead',
|
|
34
|
+
notebook_edit: 'NotebookEdit',
|
|
35
|
+
tool_search: 'ToolSearch',
|
|
36
|
+
todo_read: 'TodoRead',
|
|
37
|
+
todo_write: 'TodoWrite',
|
|
38
|
+
agent: 'Agent',
|
|
39
|
+
interactive: 'AskUserQuestion', // deferred — preload via ToolSearch first
|
|
40
|
+
},
|
|
41
|
+
interactive: 'AUQ', // must call ToolSearch before first AUQ
|
|
42
|
+
subagent: 'multi-level', // Agent tool supports nested spawning
|
|
43
|
+
orchestration: {
|
|
44
|
+
mode: 'agent-tool', // Agent tool = callable from skill
|
|
45
|
+
parallel: true,
|
|
46
|
+
teams: true, // CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
|
|
47
|
+
background: true,
|
|
48
|
+
model_override: {
|
|
49
|
+
worker: 'claude-haiku-4-5',
|
|
50
|
+
orchestrator: 'claude-sonnet-4-6',
|
|
51
|
+
},
|
|
52
|
+
max_parallel_tasks: 5,
|
|
53
|
+
},
|
|
54
|
+
hooks: {
|
|
55
|
+
count: 28,
|
|
56
|
+
supported_events: [
|
|
57
|
+
'SessionStart', 'SessionEnd', 'Stop', 'StopFailure',
|
|
58
|
+
'UserPromptSubmit', 'PreToolUse', 'PostToolUse', 'PostToolUseFailure',
|
|
59
|
+
'FileChanged', 'SubagentStart', 'SubagentStop',
|
|
60
|
+
'TaskCreated', 'TaskCompleted', 'PreCompact', 'PostCompact',
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
mcp: { supported: true, tool_limit: null },
|
|
64
|
+
skill_path_project: '.claude/skills',
|
|
65
|
+
skill_path_global: '~/.claude/skills',
|
|
66
|
+
agents_dir: '.claude/agents',
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
'cursor-agent': {
|
|
70
|
+
id: 'cursor-agent',
|
|
71
|
+
name: 'Cursor (Agent Mode)',
|
|
72
|
+
tools: {
|
|
73
|
+
shell: 'run_terminal_cmd',
|
|
74
|
+
read: 'read_file',
|
|
75
|
+
write: 'edit_file',
|
|
76
|
+
edit: 'edit_file',
|
|
77
|
+
multi_edit: 'edit_file',
|
|
78
|
+
search: 'grep_search',
|
|
79
|
+
glob: 'file_search',
|
|
80
|
+
ls: 'list_dir',
|
|
81
|
+
web_search: 'web_search',
|
|
82
|
+
web_fetch: null, // not available
|
|
83
|
+
notebook_read: null,
|
|
84
|
+
notebook_edit: null,
|
|
85
|
+
tool_search: null,
|
|
86
|
+
todo_read: null,
|
|
87
|
+
todo_write: null,
|
|
88
|
+
agent: null, // /multitask is user command, not callable tool
|
|
89
|
+
interactive: null, // AskQuestion only in Plan Mode
|
|
90
|
+
},
|
|
91
|
+
interactive: 'text', // plain-text numbered list fallback
|
|
92
|
+
subagent: 'command-only', // /multitask user cmd, single-level, not callable
|
|
93
|
+
orchestration: {
|
|
94
|
+
mode: 'sequential',
|
|
95
|
+
parallel: false,
|
|
96
|
+
teams: false,
|
|
97
|
+
background: false,
|
|
98
|
+
model_override: null,
|
|
99
|
+
max_parallel_tasks: 1,
|
|
100
|
+
},
|
|
101
|
+
hooks: {
|
|
102
|
+
count: 5,
|
|
103
|
+
supported_events: [
|
|
104
|
+
'beforeShellExecution', 'beforeMCPExecution',
|
|
105
|
+
'beforeReadFile', 'afterFileEdit', 'stop',
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
mcp: { supported: true, tool_limit: 40 },
|
|
109
|
+
skill_path_project: '.cursor/skills',
|
|
110
|
+
skill_path_global: '~/.cursor/skills',
|
|
111
|
+
agents_dir: null,
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
'antigravity': {
|
|
115
|
+
id: 'antigravity',
|
|
116
|
+
name: 'Antigravity (Google)',
|
|
117
|
+
tools: {
|
|
118
|
+
shell: 'shell',
|
|
119
|
+
read: 'file_read',
|
|
120
|
+
write: 'file_write',
|
|
121
|
+
edit: 'file_write',
|
|
122
|
+
multi_edit: 'file_write',
|
|
123
|
+
search: null, // via shell or MCP
|
|
124
|
+
glob: null, // via shell
|
|
125
|
+
ls: null, // via shell
|
|
126
|
+
web_search: null, // via MCP plugin
|
|
127
|
+
web_fetch: null, // via MCP plugin
|
|
128
|
+
notebook_read: null,
|
|
129
|
+
notebook_edit: null,
|
|
130
|
+
tool_search: null,
|
|
131
|
+
todo_read: null,
|
|
132
|
+
todo_write: null,
|
|
133
|
+
agent: null, // async TUI dispatch only
|
|
134
|
+
interactive: null, // TUI-based, no formal AUQ
|
|
135
|
+
},
|
|
136
|
+
interactive: 'none',
|
|
137
|
+
subagent: 'none',
|
|
138
|
+
orchestration: {
|
|
139
|
+
mode: 'sequential',
|
|
140
|
+
parallel: false,
|
|
141
|
+
teams: false,
|
|
142
|
+
background: false,
|
|
143
|
+
model_override: null,
|
|
144
|
+
max_parallel_tasks: 1,
|
|
145
|
+
},
|
|
146
|
+
hooks: {
|
|
147
|
+
count: 3,
|
|
148
|
+
supported_events: ['before_tool', 'after_file_edit', 'session_start'],
|
|
149
|
+
},
|
|
150
|
+
mcp: { supported: true, tool_limit: null },
|
|
151
|
+
skill_path_project: '.agents/skills',
|
|
152
|
+
skill_path_global: '~/.gemini/antigravity/skills',
|
|
153
|
+
agents_dir: null,
|
|
154
|
+
deprecation_notice: 'Gemini CLI was deprecated June 18, 2026. Use Antigravity CLI instead.',
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
'codex': {
|
|
158
|
+
id: 'codex',
|
|
159
|
+
name: 'OpenAI Codex CLI',
|
|
160
|
+
tools: {
|
|
161
|
+
shell: 'container.exec', // sandboxed shell
|
|
162
|
+
read: null, // patch-based — no explicit read tool
|
|
163
|
+
write: 'apply_patch',
|
|
164
|
+
edit: 'apply_patch',
|
|
165
|
+
multi_edit: 'apply_patch',
|
|
166
|
+
search: null, // via shell
|
|
167
|
+
glob: null, // via shell
|
|
168
|
+
ls: null, // via shell
|
|
169
|
+
web_search: 'web_search', // native or MCP
|
|
170
|
+
web_fetch: null,
|
|
171
|
+
notebook_read: null,
|
|
172
|
+
notebook_edit: null,
|
|
173
|
+
tool_search: null,
|
|
174
|
+
todo_read: null,
|
|
175
|
+
todo_write: null,
|
|
176
|
+
agent: 'subagent', // subagents supported
|
|
177
|
+
interactive: null, // TUI Tab/Enter injection only
|
|
178
|
+
},
|
|
179
|
+
interactive: 'none',
|
|
180
|
+
subagent: 'single-level',
|
|
181
|
+
orchestration: {
|
|
182
|
+
mode: 'sequential',
|
|
183
|
+
parallel: false,
|
|
184
|
+
teams: false,
|
|
185
|
+
background: false,
|
|
186
|
+
model_override: null,
|
|
187
|
+
max_parallel_tasks: 1,
|
|
188
|
+
},
|
|
189
|
+
hooks: {
|
|
190
|
+
count: 0,
|
|
191
|
+
supported_events: [],
|
|
192
|
+
},
|
|
193
|
+
mcp: { supported: true, tool_limit: null },
|
|
194
|
+
skill_path_project: null,
|
|
195
|
+
skill_path_global: '~/.codex',
|
|
196
|
+
agents_dir: null,
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
'copilot': {
|
|
200
|
+
id: 'copilot',
|
|
201
|
+
name: 'GitHub Copilot',
|
|
202
|
+
tools: {
|
|
203
|
+
shell: 'runCommands',
|
|
204
|
+
read: 'read',
|
|
205
|
+
write: 'editFiles',
|
|
206
|
+
edit: 'edit',
|
|
207
|
+
multi_edit: 'editFiles',
|
|
208
|
+
search: 'code_search',
|
|
209
|
+
glob: null,
|
|
210
|
+
ls: null,
|
|
211
|
+
web_search: null,
|
|
212
|
+
web_fetch: null,
|
|
213
|
+
notebook_read: null,
|
|
214
|
+
notebook_edit: null,
|
|
215
|
+
tool_search: null,
|
|
216
|
+
todo_read: null,
|
|
217
|
+
todo_write: null,
|
|
218
|
+
agent: null, // explore/task are built-in agents, not callable
|
|
219
|
+
// askQuestions available in main agent ONLY — not in subagents (VS Code #293745)
|
|
220
|
+
interactive: 'askQuestions',
|
|
221
|
+
},
|
|
222
|
+
interactive: 'text', // askQuestions not available in subagents
|
|
223
|
+
subagent: 'none',
|
|
224
|
+
orchestration: {
|
|
225
|
+
mode: 'sequential',
|
|
226
|
+
parallel: false,
|
|
227
|
+
teams: false,
|
|
228
|
+
background: false,
|
|
229
|
+
model_override: null,
|
|
230
|
+
max_parallel_tasks: 1,
|
|
231
|
+
},
|
|
232
|
+
hooks: {
|
|
233
|
+
count: 0,
|
|
234
|
+
supported_events: [],
|
|
235
|
+
},
|
|
236
|
+
mcp: { supported: true, tool_limit: null },
|
|
237
|
+
skill_path_project: '.github/agents',
|
|
238
|
+
skill_path_global: null,
|
|
239
|
+
agents_dir: '.github/agents',
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Aliases
|
|
244
|
+
ADAPTER_CONTEXTS['cursor'] = ADAPTER_CONTEXTS['cursor-agent'];
|
|
245
|
+
ADAPTER_CONTEXTS['cursor-ide'] = ADAPTER_CONTEXTS['cursor-agent'];
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get ADAPTER_CONTEXT for a given adapter ID. Throws if unknown.
|
|
249
|
+
*/
|
|
250
|
+
function getAdapterContext(id) {
|
|
251
|
+
const ctx = ADAPTER_CONTEXTS[id];
|
|
252
|
+
if (!ctx) {
|
|
253
|
+
throw new Error(`Unknown adapter: "${id}". Known: ${Object.keys(ADAPTER_CONTEXTS).filter(k => !['cursor','cursor-ide'].includes(k)).join(', ')}`);
|
|
254
|
+
}
|
|
255
|
+
return ctx;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* List all canonical adapter IDs (no aliases).
|
|
260
|
+
*/
|
|
261
|
+
function listAdapterIds() {
|
|
262
|
+
return ['claude-code', 'cursor-agent', 'antigravity', 'codex', 'copilot'];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Detect the active adapter from environment heuristics.
|
|
267
|
+
* Returns the adapter ID string.
|
|
268
|
+
*/
|
|
269
|
+
function detectAdapter() {
|
|
270
|
+
const env = process.env;
|
|
271
|
+
|
|
272
|
+
// Env-var signals (strongest signals first)
|
|
273
|
+
if (env.CURSOR_TRACE || env.CURSOR_CHANNEL || env.CURSOR_ENABLED) return 'cursor-agent';
|
|
274
|
+
if (env.ANTIGRAVITY_SESSION || env.GEMINI_ANTIGRAVITY_SESSION) return 'antigravity';
|
|
275
|
+
if (env.CODEX_SESSION || env.OPENAI_CODEX_SESSION) return 'codex';
|
|
276
|
+
if (env.GITHUB_COPILOT_AGENT || env.COPILOT_AGENT) return 'copilot';
|
|
277
|
+
|
|
278
|
+
// TERM_PROGRAM / process name signals
|
|
279
|
+
const termProgram = (env.TERM_PROGRAM || '').toLowerCase();
|
|
280
|
+
if (termProgram === 'claude' || termProgram === 'claude-code') return 'claude-code';
|
|
281
|
+
|
|
282
|
+
// ~/.claude directory exists → likely Claude Code
|
|
283
|
+
const os = require('os');
|
|
284
|
+
const fs = require('fs');
|
|
285
|
+
const path = require('path');
|
|
286
|
+
const home = os.homedir();
|
|
287
|
+
if (fs.existsSync(path.join(home, '.claude', 'settings.json'))) return 'claude-code';
|
|
288
|
+
if (fs.existsSync(path.join(home, '.claude'))) return 'claude-code';
|
|
289
|
+
|
|
290
|
+
// Fallback: claude-code (most common in ViePilot context)
|
|
291
|
+
return 'claude-code';
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
module.exports = { ADAPTER_CONTEXTS, getAdapterContext, listAdapterIds, detectAdapter };
|
|
@@ -6,16 +6,21 @@ const fs = require('fs');
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
id: 'antigravity',
|
|
8
8
|
name: 'Antigravity',
|
|
9
|
+
// Global install path (unchanged)
|
|
9
10
|
skillsDir: (home) => path.join(home, '.gemini', 'antigravity', 'skills'),
|
|
10
11
|
viepilotDir: (home) => path.join(home, '.gemini', 'antigravity', 'viepilot'),
|
|
12
|
+
// Phase 131 (FEAT-021): project-level install path (Antigravity v1 uses .agents/skills/)
|
|
13
|
+
projectSkillsDir: '.agents/skills',
|
|
11
14
|
// {envToolDir} in SKILL.md files resolves to this value at install time (ENH-035)
|
|
12
15
|
executionContextBase: '.gemini/antigravity/viepilot',
|
|
13
16
|
// Post-install hint shown in "Next actions" after viepilot install
|
|
14
17
|
postInstallHint: 'Open project and run /vp-status',
|
|
18
|
+
// Phase 131 (FEAT-021): Gemini CLI was deprecated June 18, 2026
|
|
19
|
+
deprecationNotice: '⚠️ Gemini CLI was deprecated June 18, 2026. This installs for Antigravity CLI (the successor). Skill path: .agents/skills/ (project) or ~/.gemini/antigravity/skills/ (global).',
|
|
15
20
|
hooks: {
|
|
16
21
|
configFile: null, // Antigravity has no programmatic hooks system
|
|
17
22
|
schema: 'antigravity',
|
|
18
|
-
supportedEvents: []
|
|
23
|
+
supportedEvents: ['before_tool', 'after_file_edit', 'session_start']
|
|
19
24
|
},
|
|
20
25
|
installSubdirs: [
|
|
21
26
|
'workflows',
|
|
@@ -30,6 +35,7 @@ module.exports = {
|
|
|
30
35
|
isAvailable: (home) => {
|
|
31
36
|
const h = home || os.homedir();
|
|
32
37
|
return fs.existsSync(path.join(h, '.gemini', 'antigravity'))
|
|
33
|
-
|| fs.existsSync(path.join(h, '.antigravity'))
|
|
38
|
+
|| fs.existsSync(path.join(h, '.antigravity'))
|
|
39
|
+
|| fs.existsSync(path.join(process.cwd(), '.agents'));
|
|
34
40
|
}
|
|
35
41
|
};
|
|
@@ -35,6 +35,10 @@ module.exports = {
|
|
|
35
35
|
'ui-components',
|
|
36
36
|
'agents'
|
|
37
37
|
],
|
|
38
|
+
// Phase 130 (FEAT-021): native Claude Code subagent definitions (.claude/agents/)
|
|
39
|
+
// Installed to ~/.claude/agents/ (Claude Code's native agent directory)
|
|
40
|
+
claudeAgentsDir: (home) => path.join(home, '.claude', 'agents'),
|
|
41
|
+
claudeAgentsSrc: 'agents/claude-code',
|
|
38
42
|
// Detection: is this platform available on the current machine?
|
|
39
43
|
isAvailable: (home) => {
|
|
40
44
|
const h = home || os.homedir();
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_BASE_URL = 'http://localhost:3000';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve base URL for browser audit.
|
|
10
|
+
* Priority: options.baseUrl → config.json audit.baseUrl → DEFAULT_BASE_URL
|
|
11
|
+
* @param {object} options - { baseUrl?: string }
|
|
12
|
+
* @param {string} projectRoot
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
function resolveBaseUrl(options, projectRoot) {
|
|
16
|
+
if (options && options.baseUrl) return options.baseUrl;
|
|
17
|
+
try {
|
|
18
|
+
const configPath = path.join(projectRoot, '.viepilot', 'config.json');
|
|
19
|
+
if (fs.existsSync(configPath)) {
|
|
20
|
+
const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
21
|
+
if (cfg.audit && cfg.audit.baseUrl) return cfg.audit.baseUrl;
|
|
22
|
+
}
|
|
23
|
+
} catch { /* config missing or malformed — use default */ }
|
|
24
|
+
return DEFAULT_BASE_URL;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Write a Markdown audit report to .viepilot/audit/visual-report-{timestamp}.md
|
|
29
|
+
* @param {object} report - structured audit report from browser-audit-agent
|
|
30
|
+
* @param {string} projectRoot
|
|
31
|
+
* @returns {string} absolute path to report file
|
|
32
|
+
*/
|
|
33
|
+
function writeAuditReport(report, projectRoot) {
|
|
34
|
+
const auditDir = path.join(projectRoot, '.viepilot', 'audit');
|
|
35
|
+
fs.mkdirSync(auditDir, { recursive: true });
|
|
36
|
+
|
|
37
|
+
const timestamp = Date.now();
|
|
38
|
+
const reportPath = path.join(auditDir, `visual-report-${timestamp}.md`);
|
|
39
|
+
|
|
40
|
+
const routes = report.routes || [];
|
|
41
|
+
const routeTable = routes.map(r => {
|
|
42
|
+
const status = r.status === 'ok' ? '✅ ok' : `❌ ${r.status}`;
|
|
43
|
+
const issues = (r.errors && r.errors.length > 0) ? r.errors.join(', ') : '—';
|
|
44
|
+
return `| ${r.url} | ${status} | ${issues} |`;
|
|
45
|
+
}).join('\n');
|
|
46
|
+
|
|
47
|
+
const accessibilitySection = routes
|
|
48
|
+
.filter(r => r.accessibility_issues && r.accessibility_issues.length > 0)
|
|
49
|
+
.map(r => `### ${r.url}\n${r.accessibility_issues.map(i => `- **${i.type}**: ${i.description}`).join('\n')}`)
|
|
50
|
+
.join('\n\n') || '_No accessibility issues found._';
|
|
51
|
+
|
|
52
|
+
const screenshotSection = routes
|
|
53
|
+
.filter(r => r.screenshot)
|
|
54
|
+
.map(r => `- \`${r.url}\`: \`${r.screenshot}\``)
|
|
55
|
+
.join('\n') || '_No screenshots captured._';
|
|
56
|
+
|
|
57
|
+
const content = `# Browser Audit Report — ${new Date(timestamp).toISOString()}
|
|
58
|
+
|
|
59
|
+
**Base URL**: ${report.baseUrl || DEFAULT_BASE_URL}
|
|
60
|
+
**Routes checked**: ${routes.length}
|
|
61
|
+
**Op**: ${report.op || 'audit_routes'}
|
|
62
|
+
|
|
63
|
+
## Routes
|
|
64
|
+
|
|
65
|
+
| Route | Status | Issues |
|
|
66
|
+
|-------|--------|--------|
|
|
67
|
+
${routeTable}
|
|
68
|
+
|
|
69
|
+
## Accessibility Issues
|
|
70
|
+
|
|
71
|
+
${accessibilitySection}
|
|
72
|
+
|
|
73
|
+
## Screenshots
|
|
74
|
+
|
|
75
|
+
${screenshotSection}
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
fs.writeFileSync(reportPath, content, 'utf8');
|
|
79
|
+
return reportPath;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Run browser audit by dispatching browser-audit-agent (CC adapter only).
|
|
84
|
+
* On non-CC: throws with install instructions.
|
|
85
|
+
* @param {object} options - { baseUrl?, routes?, op?, updateBaseline? }
|
|
86
|
+
* @param {string} projectRoot
|
|
87
|
+
* @returns {Promise<object>} - report object
|
|
88
|
+
*/
|
|
89
|
+
async function runBrowserAudit(options, projectRoot) {
|
|
90
|
+
const baseUrl = resolveBaseUrl(options, projectRoot);
|
|
91
|
+
const op = (options && options.op) || 'audit_routes';
|
|
92
|
+
|
|
93
|
+
// CC adapter: Agent dispatch is handled by vp-audit SKILL.md (orchestrator layer).
|
|
94
|
+
// This module is for direct Node callers — emit clear error.
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Browser audit requires Claude Code with the agent-browser skill.\n` +
|
|
97
|
+
`Install: npx skills add vercel-labs/agent-browser\n` +
|
|
98
|
+
`Then run: /vp-audit --visual --browser ${baseUrl}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = { runBrowserAudit, resolveBaseUrl, writeAuditReport, DEFAULT_BASE_URL };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const URL_PATTERNS = {
|
|
4
|
+
'google-sheets': /docs\.google\.com\/spreadsheets/,
|
|
5
|
+
'github-issues': /github\.com\/[^/]+\/[^/]+\/issues/,
|
|
6
|
+
'jira': /atlassian\.net\/browse\/[A-Z]+-\d+|atlassian\.net\/jira\/software\/projects/,
|
|
7
|
+
'trello': /trello\.com\/[bc]\//,
|
|
8
|
+
'notion': /notion\.so\/[a-f0-9]{8,}/,
|
|
9
|
+
'sharepoint-xlsx': /sharepoint\.com\/:[a-z]:\/[a-z]\//,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Detect source type from URL string.
|
|
14
|
+
* @param {string} url
|
|
15
|
+
* @returns {'google-sheets'|'github-issues'|'jira'|'trello'|'notion'|'sharepoint-xlsx'|'generic-table'}
|
|
16
|
+
*/
|
|
17
|
+
function detectUrlType(url) {
|
|
18
|
+
if (!url || typeof url !== 'string') return 'generic-table';
|
|
19
|
+
for (const [type, pattern] of Object.entries(URL_PATTERNS)) {
|
|
20
|
+
if (pattern.test(url)) return type;
|
|
21
|
+
}
|
|
22
|
+
return 'generic-table';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Read ticket rows from a public URL via browser-intake-agent (CC adapter only).
|
|
27
|
+
* Non-CC adapters receive a clear unsupported error.
|
|
28
|
+
* @param {object} channel - channel config with `url` field
|
|
29
|
+
* @param {string} projectRoot - absolute path to project root
|
|
30
|
+
* @returns {Promise<Array<{title,description,labels,priority,status}>>}
|
|
31
|
+
*/
|
|
32
|
+
async function readBrowserUrl(channel, projectRoot) {
|
|
33
|
+
if (!channel || !channel.url) {
|
|
34
|
+
throw new Error('browser channel requires a "url" field in channel config');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const sourceType = detectUrlType(channel.url);
|
|
38
|
+
|
|
39
|
+
// CC adapter: Agent dispatch is handled by vp-intake SKILL.md (orchestrator layer).
|
|
40
|
+
// This module is used by non-CC adapters or direct Node callers — emit clear error.
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Browser channel (${sourceType}) requires Claude Code with the agent-browser skill.\n` +
|
|
43
|
+
`Install: npx skills add vercel-labs/agent-browser\n` +
|
|
44
|
+
`Then run vp-intake from Claude Code.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check whether a URL appears to be a publicly accessible intake source.
|
|
50
|
+
* Does not make network requests — pattern-match only.
|
|
51
|
+
* @param {string} url
|
|
52
|
+
* @returns {boolean}
|
|
53
|
+
*/
|
|
54
|
+
function isKnownPublicSource(url) {
|
|
55
|
+
return detectUrlType(url) !== 'generic-table';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { readBrowserUrl, detectUrlType, isKnownPublicSource, URL_PATTERNS };
|