vibe-forge 0.8.2 → 0.8.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/.claude/commands/clear-attention.md +63 -63
- package/.claude/commands/compact-context.md +52 -52
- package/.claude/commands/need-help.md +77 -77
- package/.claude/commands/update-status.md +64 -64
- package/.claude/commands/worker-loop.md +106 -106
- package/.claude/scripts/setup-worker-loop.sh +45 -45
- package/LICENSE +21 -21
- package/README.md +211 -211
- package/bin/cli.js +127 -33
- package/bin/dashboard/api/agents.js +333 -333
- package/bin/dashboard/api/dispatch.js +507 -507
- package/bin/dashboard/api/tasks.js +416 -416
- package/bin/dashboard/public/assets/index-Dm2PgE2m.js +2 -0
- package/bin/dashboard/public/index.html +13 -13
- package/bin/dashboard/server.js +574 -645
- package/config/agent-manifest.yaml +237 -237
- package/config/agents.json +207 -207
- package/config/task-types.yaml +111 -111
- package/context/agent-overrides/README.md +41 -41
- package/context/architecture.md +42 -42
- package/context/modern-conventions.md +129 -129
- package/docs/agents.md +473 -473
- package/docs/architecture.md +194 -194
- package/docs/commands.md +451 -451
- package/docs/security.md +195 -195
- package/package.json +2 -3
- package/src/lib/database.sh +1 -1
- package/bin/dashboard/public/assets/index-BpHfsx1r.js +0 -2
package/README.md
CHANGED
|
@@ -1,211 +1,211 @@
|
|
|
1
|
-
# Vibe Forge
|
|
2
|
-
|
|
3
|
-
A multi-agent development orchestration system for terminal-native vibe coding.
|
|
4
|
-
|
|
5
|
-
## What Is This?
|
|
6
|
-
|
|
7
|
-
Vibe Forge transforms your terminal into a collaborative AI development environment. Multiple Claude agents, each with distinct personalities and specializations, work together to build software. You talk to a Planning Hub that coordinates the team, then spawn workers into separate terminal tabs to execute in parallel.
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
YOU
|
|
11
|
-
|
|
|
12
|
-
/forge plan
|
|
13
|
-
|
|
|
14
|
-
+-----------+-----------+
|
|
15
|
-
| PLANNING HUB |
|
|
16
|
-
| Oracle Architect |
|
|
17
|
-
| Aegis Pixel |
|
|
18
|
-
| Ember Crucible |
|
|
19
|
-
+-----------+-----------+
|
|
20
|
-
|
|
|
21
|
-
/forge spawn <agent>
|
|
22
|
-
|
|
|
23
|
-
+--------+-------+-------+--------+
|
|
24
|
-
| | | | |
|
|
25
|
-
Anvil Furnace Crucible Temper Scribe
|
|
26
|
-
FE BE QA Review Docs
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Install
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npx vibe-forge init
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
This sets up Vibe Forge in your project: detects your platform, configures your terminal, creates project context files, and installs the `/forge` slash command into Claude Code.
|
|
36
|
-
|
|
37
|
-
**Prerequisites:** [Claude Code CLI](https://claude.ai/download), Node.js 18+, Git
|
|
38
|
-
|
|
39
|
-
## Quick Start
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
# Start the Planning Hub (multi-expert planning session)
|
|
43
|
-
/forge
|
|
44
|
-
|
|
45
|
-
# Or jump straight to planning a feature
|
|
46
|
-
/forge plan user authentication
|
|
47
|
-
|
|
48
|
-
# Spawn a worker agent in a new terminal tab
|
|
49
|
-
/forge spawn anvil
|
|
50
|
-
|
|
51
|
-
# Check what's happening
|
|
52
|
-
/forge status
|
|
53
|
-
|
|
54
|
-
# See all commands
|
|
55
|
-
/forge help
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Agents
|
|
59
|
-
|
|
60
|
-
### Planning Hub (Your Terminal)
|
|
61
|
-
|
|
62
|
-
When you run `/forge`, a multi-voice planning session starts. These expert voices collaborate to help you scope, design, and decompose work:
|
|
63
|
-
|
|
64
|
-
| Voice | Icon | Speaks When |
|
|
65
|
-
|-------|------|-------------|
|
|
66
|
-
| Forge Master | :fire: | Tasks, assignments, workflow, coordination |
|
|
67
|
-
| Architect | :classical_building: | Architecture, patterns, tech decisions |
|
|
68
|
-
| Aegis | :shield: | Auth, security, vulnerabilities |
|
|
69
|
-
| Ember | :gear: | DevOps, CI/CD, deployment |
|
|
70
|
-
| Pixel | :art: | UX, user flows, accessibility |
|
|
71
|
-
| Oracle | :bar_chart: | Requirements, scope, priorities |
|
|
72
|
-
| Crucible | :test_tube: | Edge cases, test strategy, quality |
|
|
73
|
-
| Loki | :performing_arts: | Challenges assumptions, lateral thinking |
|
|
74
|
-
|
|
75
|
-
### Worker Agents (Separate Terminals)
|
|
76
|
-
|
|
77
|
-
Spawn these into new terminal tabs to execute tasks:
|
|
78
|
-
|
|
79
|
-
| Agent | Aliases | Role |
|
|
80
|
-
|-------|---------|------|
|
|
81
|
-
| anvil | frontend, ui, fe | Frontend Developer |
|
|
82
|
-
| furnace | backend, api, be | Backend Developer |
|
|
83
|
-
| crucible | test, qa | Tester / QA |
|
|
84
|
-
| scribe | docs, documentation | Documentation |
|
|
85
|
-
| herald | release, deploy | Release Manager |
|
|
86
|
-
| ember | devops, infra | DevOps Engineer |
|
|
87
|
-
|
|
88
|
-
### Review Agents
|
|
89
|
-
|
|
90
|
-
| Agent | Aliases | Role |
|
|
91
|
-
|-------|---------|------|
|
|
92
|
-
| temper | review, cr | Code Reviewer (compliance + correctness) |
|
|
93
|
-
| crucible-x | adversarial, cx | Adversarial Reviewer (tries to break it) |
|
|
94
|
-
|
|
95
|
-
### Specialists
|
|
96
|
-
|
|
97
|
-
| Agent | Aliases | Role |
|
|
98
|
-
|-------|---------|------|
|
|
99
|
-
| architect | arch, sage | System Architect |
|
|
100
|
-
| aegis | security, sec | Security Specialist |
|
|
101
|
-
| pixel | ux, ui-design | UX Designer |
|
|
102
|
-
| oracle | product, po | Product Owner |
|
|
103
|
-
| loki | brainstorm, contrarian | Assumption Challenger |
|
|
104
|
-
|
|
105
|
-
### Red Team
|
|
106
|
-
|
|
107
|
-
| Agent | Aliases | Role |
|
|
108
|
-
|-------|---------|------|
|
|
109
|
-
| slag | redteam, pentest | Red Team Lead |
|
|
110
|
-
| flux | infra-sec, chaos | Infrastructure Security |
|
|
111
|
-
|
|
112
|
-
## How It Works
|
|
113
|
-
|
|
114
|
-
### Planning Mode
|
|
115
|
-
|
|
116
|
-
When you describe a goal, the Hub enters a 4-phase planning flow:
|
|
117
|
-
|
|
118
|
-
1. **Discovery** - Oracle asks clarifying questions about users, goals, constraints
|
|
119
|
-
2. **Decomposition** - Architect breaks the goal into epics with success metrics
|
|
120
|
-
3. **Tasking** - Forge Master creates stories and tasks, assigns to agents
|
|
121
|
-
4. **Commit** - Epic and task files written to disk, ready for workers
|
|
122
|
-
|
|
123
|
-
### Task System
|
|
124
|
-
|
|
125
|
-
Tasks flow through folders on disk. No database required.
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
pending/ -> in-progress/ -> completed/ -> review/ -> approved/ -> merged/
|
|
129
|
-
|
|
|
130
|
-
needs-changes/ (back to worker)
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Workers pick up tasks from `pending/` on startup. Temper reviews completed work. The daemon routes tasks automatically.
|
|
134
|
-
|
|
135
|
-
### Daemon
|
|
136
|
-
|
|
137
|
-
An optional background daemon monitors the forge:
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
./bin/forge.sh daemon start # Start background monitoring
|
|
141
|
-
./bin/forge.sh daemon status # Check what's happening
|
|
142
|
-
./bin/forge.sh daemon stop # Stop the daemon
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
The daemon provides:
|
|
146
|
-
- Task routing between folders
|
|
147
|
-
- Agent status tracking
|
|
148
|
-
- Token budget warnings for long-running agents
|
|
149
|
-
- Dependency resolution (respects `blocked_by` in task files)
|
|
150
|
-
- Attention notifications when agents need help
|
|
151
|
-
|
|
152
|
-
### Dashboard
|
|
153
|
-
|
|
154
|
-
A web dashboard at `http://localhost:2800` shows:
|
|
155
|
-
- Task counts and status
|
|
156
|
-
- Agent activity feed
|
|
157
|
-
- Issue detection
|
|
158
|
-
- Real-time updates via WebSocket
|
|
159
|
-
|
|
160
|
-
### Per-Project Customization
|
|
161
|
-
|
|
162
|
-
Add agent-specific rules for your project in `context/agent-overrides/`:
|
|
163
|
-
|
|
164
|
-
```markdown
|
|
165
|
-
<!-- context/agent-overrides/anvil.md -->
|
|
166
|
-
- Use Tailwind CSS, no custom CSS files
|
|
167
|
-
- All components in src/components/ with PascalCase
|
|
168
|
-
- Use shadcn/ui for base components
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
These rules are injected into the agent's system prompt at spawn time.
|
|
172
|
-
|
|
173
|
-
## Project Structure
|
|
174
|
-
|
|
175
|
-
```
|
|
176
|
-
your-project/
|
|
177
|
-
_vibe-forge/
|
|
178
|
-
agents/ # Agent personalities (16 agents)
|
|
179
|
-
bin/ # CLI, daemon, dashboard, spawn scripts
|
|
180
|
-
config/ # agents.json, task templates
|
|
181
|
-
context/ # Project context, agent overrides
|
|
182
|
-
specs/ # Epics and stories
|
|
183
|
-
tasks/ # Task lifecycle folders
|
|
184
|
-
docs/ # Security, architecture, agent docs
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## Commands Reference
|
|
188
|
-
|
|
189
|
-
| Command | Description |
|
|
190
|
-
|---------|-------------|
|
|
191
|
-
| `/forge` | Start the Planning Hub |
|
|
192
|
-
| `/forge plan <feature>` | Plan a feature with the full team |
|
|
193
|
-
| `/forge status` | Show status dashboard |
|
|
194
|
-
| `/forge spawn <agent>` | Spawn worker in new terminal |
|
|
195
|
-
| `/forge task [desc]` | Create a new task |
|
|
196
|
-
| `/forge redteam [scope]` | Launch red team engagement |
|
|
197
|
-
| `/forge help` | Show all commands |
|
|
198
|
-
|
|
199
|
-
## Security
|
|
200
|
-
|
|
201
|
-
Vibe Forge uses a defense-in-depth permission model:
|
|
202
|
-
|
|
203
|
-
1. **Allowlist** (`.claude/settings.json`) - Pre-approves safe operations
|
|
204
|
-
2. **Heimdall** (pre-tool hook) - Enforces forge policies (branch protection, naming)
|
|
205
|
-
3. **Claude Code prompts** - Anything not allowlisted still requires approval
|
|
206
|
-
|
|
207
|
-
See [docs/security.md](docs/security.md) for the full security model.
|
|
208
|
-
|
|
209
|
-
## License
|
|
210
|
-
|
|
211
|
-
MIT
|
|
1
|
+
# Vibe Forge
|
|
2
|
+
|
|
3
|
+
A multi-agent development orchestration system for terminal-native vibe coding.
|
|
4
|
+
|
|
5
|
+
## What Is This?
|
|
6
|
+
|
|
7
|
+
Vibe Forge transforms your terminal into a collaborative AI development environment. Multiple Claude agents, each with distinct personalities and specializations, work together to build software. You talk to a Planning Hub that coordinates the team, then spawn workers into separate terminal tabs to execute in parallel.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
YOU
|
|
11
|
+
|
|
|
12
|
+
/forge plan
|
|
13
|
+
|
|
|
14
|
+
+-----------+-----------+
|
|
15
|
+
| PLANNING HUB |
|
|
16
|
+
| Oracle Architect |
|
|
17
|
+
| Aegis Pixel |
|
|
18
|
+
| Ember Crucible |
|
|
19
|
+
+-----------+-----------+
|
|
20
|
+
|
|
|
21
|
+
/forge spawn <agent>
|
|
22
|
+
|
|
|
23
|
+
+--------+-------+-------+--------+
|
|
24
|
+
| | | | |
|
|
25
|
+
Anvil Furnace Crucible Temper Scribe
|
|
26
|
+
FE BE QA Review Docs
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx vibe-forge init
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This sets up Vibe Forge in your project: detects your platform, configures your terminal, creates project context files, and installs the `/forge` slash command into Claude Code.
|
|
36
|
+
|
|
37
|
+
**Prerequisites:** [Claude Code CLI](https://claude.ai/download), Node.js 18+, Git
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Start the Planning Hub (multi-expert planning session)
|
|
43
|
+
/forge
|
|
44
|
+
|
|
45
|
+
# Or jump straight to planning a feature
|
|
46
|
+
/forge plan user authentication
|
|
47
|
+
|
|
48
|
+
# Spawn a worker agent in a new terminal tab
|
|
49
|
+
/forge spawn anvil
|
|
50
|
+
|
|
51
|
+
# Check what's happening
|
|
52
|
+
/forge status
|
|
53
|
+
|
|
54
|
+
# See all commands
|
|
55
|
+
/forge help
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Agents
|
|
59
|
+
|
|
60
|
+
### Planning Hub (Your Terminal)
|
|
61
|
+
|
|
62
|
+
When you run `/forge`, a multi-voice planning session starts. These expert voices collaborate to help you scope, design, and decompose work:
|
|
63
|
+
|
|
64
|
+
| Voice | Icon | Speaks When |
|
|
65
|
+
|-------|------|-------------|
|
|
66
|
+
| Forge Master | :fire: | Tasks, assignments, workflow, coordination |
|
|
67
|
+
| Architect | :classical_building: | Architecture, patterns, tech decisions |
|
|
68
|
+
| Aegis | :shield: | Auth, security, vulnerabilities |
|
|
69
|
+
| Ember | :gear: | DevOps, CI/CD, deployment |
|
|
70
|
+
| Pixel | :art: | UX, user flows, accessibility |
|
|
71
|
+
| Oracle | :bar_chart: | Requirements, scope, priorities |
|
|
72
|
+
| Crucible | :test_tube: | Edge cases, test strategy, quality |
|
|
73
|
+
| Loki | :performing_arts: | Challenges assumptions, lateral thinking |
|
|
74
|
+
|
|
75
|
+
### Worker Agents (Separate Terminals)
|
|
76
|
+
|
|
77
|
+
Spawn these into new terminal tabs to execute tasks:
|
|
78
|
+
|
|
79
|
+
| Agent | Aliases | Role |
|
|
80
|
+
|-------|---------|------|
|
|
81
|
+
| anvil | frontend, ui, fe | Frontend Developer |
|
|
82
|
+
| furnace | backend, api, be | Backend Developer |
|
|
83
|
+
| crucible | test, qa | Tester / QA |
|
|
84
|
+
| scribe | docs, documentation | Documentation |
|
|
85
|
+
| herald | release, deploy | Release Manager |
|
|
86
|
+
| ember | devops, infra | DevOps Engineer |
|
|
87
|
+
|
|
88
|
+
### Review Agents
|
|
89
|
+
|
|
90
|
+
| Agent | Aliases | Role |
|
|
91
|
+
|-------|---------|------|
|
|
92
|
+
| temper | review, cr | Code Reviewer (compliance + correctness) |
|
|
93
|
+
| crucible-x | adversarial, cx | Adversarial Reviewer (tries to break it) |
|
|
94
|
+
|
|
95
|
+
### Specialists
|
|
96
|
+
|
|
97
|
+
| Agent | Aliases | Role |
|
|
98
|
+
|-------|---------|------|
|
|
99
|
+
| architect | arch, sage | System Architect |
|
|
100
|
+
| aegis | security, sec | Security Specialist |
|
|
101
|
+
| pixel | ux, ui-design | UX Designer |
|
|
102
|
+
| oracle | product, po | Product Owner |
|
|
103
|
+
| loki | brainstorm, contrarian | Assumption Challenger |
|
|
104
|
+
|
|
105
|
+
### Red Team
|
|
106
|
+
|
|
107
|
+
| Agent | Aliases | Role |
|
|
108
|
+
|-------|---------|------|
|
|
109
|
+
| slag | redteam, pentest | Red Team Lead |
|
|
110
|
+
| flux | infra-sec, chaos | Infrastructure Security |
|
|
111
|
+
|
|
112
|
+
## How It Works
|
|
113
|
+
|
|
114
|
+
### Planning Mode
|
|
115
|
+
|
|
116
|
+
When you describe a goal, the Hub enters a 4-phase planning flow:
|
|
117
|
+
|
|
118
|
+
1. **Discovery** - Oracle asks clarifying questions about users, goals, constraints
|
|
119
|
+
2. **Decomposition** - Architect breaks the goal into epics with success metrics
|
|
120
|
+
3. **Tasking** - Forge Master creates stories and tasks, assigns to agents
|
|
121
|
+
4. **Commit** - Epic and task files written to disk, ready for workers
|
|
122
|
+
|
|
123
|
+
### Task System
|
|
124
|
+
|
|
125
|
+
Tasks flow through folders on disk. No database required.
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
pending/ -> in-progress/ -> completed/ -> review/ -> approved/ -> merged/
|
|
129
|
+
|
|
|
130
|
+
needs-changes/ (back to worker)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Workers pick up tasks from `pending/` on startup. Temper reviews completed work. The daemon routes tasks automatically.
|
|
134
|
+
|
|
135
|
+
### Daemon
|
|
136
|
+
|
|
137
|
+
An optional background daemon monitors the forge:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
./bin/forge.sh daemon start # Start background monitoring
|
|
141
|
+
./bin/forge.sh daemon status # Check what's happening
|
|
142
|
+
./bin/forge.sh daemon stop # Stop the daemon
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The daemon provides:
|
|
146
|
+
- Task routing between folders
|
|
147
|
+
- Agent status tracking
|
|
148
|
+
- Token budget warnings for long-running agents
|
|
149
|
+
- Dependency resolution (respects `blocked_by` in task files)
|
|
150
|
+
- Attention notifications when agents need help
|
|
151
|
+
|
|
152
|
+
### Dashboard
|
|
153
|
+
|
|
154
|
+
A web dashboard at `http://localhost:2800` shows:
|
|
155
|
+
- Task counts and status
|
|
156
|
+
- Agent activity feed
|
|
157
|
+
- Issue detection
|
|
158
|
+
- Real-time updates via WebSocket
|
|
159
|
+
|
|
160
|
+
### Per-Project Customization
|
|
161
|
+
|
|
162
|
+
Add agent-specific rules for your project in `context/agent-overrides/`:
|
|
163
|
+
|
|
164
|
+
```markdown
|
|
165
|
+
<!-- context/agent-overrides/anvil.md -->
|
|
166
|
+
- Use Tailwind CSS, no custom CSS files
|
|
167
|
+
- All components in src/components/ with PascalCase
|
|
168
|
+
- Use shadcn/ui for base components
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
These rules are injected into the agent's system prompt at spawn time.
|
|
172
|
+
|
|
173
|
+
## Project Structure
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
your-project/
|
|
177
|
+
_vibe-forge/
|
|
178
|
+
agents/ # Agent personalities (16 agents)
|
|
179
|
+
bin/ # CLI, daemon, dashboard, spawn scripts
|
|
180
|
+
config/ # agents.json, task templates
|
|
181
|
+
context/ # Project context, agent overrides
|
|
182
|
+
specs/ # Epics and stories
|
|
183
|
+
tasks/ # Task lifecycle folders
|
|
184
|
+
docs/ # Security, architecture, agent docs
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Commands Reference
|
|
188
|
+
|
|
189
|
+
| Command | Description |
|
|
190
|
+
|---------|-------------|
|
|
191
|
+
| `/forge` | Start the Planning Hub |
|
|
192
|
+
| `/forge plan <feature>` | Plan a feature with the full team |
|
|
193
|
+
| `/forge status` | Show status dashboard |
|
|
194
|
+
| `/forge spawn <agent>` | Spawn worker in new terminal |
|
|
195
|
+
| `/forge task [desc]` | Create a new task |
|
|
196
|
+
| `/forge redteam [scope]` | Launch red team engagement |
|
|
197
|
+
| `/forge help` | Show all commands |
|
|
198
|
+
|
|
199
|
+
## Security
|
|
200
|
+
|
|
201
|
+
Vibe Forge uses a defense-in-depth permission model:
|
|
202
|
+
|
|
203
|
+
1. **Allowlist** (`.claude/settings.json`) - Pre-approves safe operations
|
|
204
|
+
2. **Heimdall** (pre-tool hook) - Enforces forge policies (branch protection, naming)
|
|
205
|
+
3. **Claude Code prompts** - Anything not allowlisted still requires approval
|
|
206
|
+
|
|
207
|
+
See [docs/security.md](docs/security.md) for the full security model.
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|
package/bin/cli.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* npx vibe-forge --help Show help
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
const { execSync, spawn } = require('child_process');
|
|
12
|
+
const { execSync, spawn, spawnSync } = require('child_process');
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const path = require('path');
|
|
15
15
|
const os = require('os');
|
|
@@ -20,6 +20,72 @@ const VERSION = packageJson.version;
|
|
|
20
20
|
const REPO_URL = 'https://github.com/sugar-crash-studios/vibe-forge.git';
|
|
21
21
|
const FORGE_DIR = '_vibe-forge';
|
|
22
22
|
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Environment allowlist for child processes.
|
|
25
|
+
//
|
|
26
|
+
// forge-setup.sh runs with full user privileges, so we pass only the minimum
|
|
27
|
+
// env it needs instead of the entire parent environment. This keeps ambient
|
|
28
|
+
// secrets (AWS_*, GITHUB_TOKEN, NPM_TOKEN, OPENAI_API_KEY, ANTHROPIC_API_KEY,
|
|
29
|
+
// DATABASE_URL, STRIPE_*, etc.) from leaking into setup scripts if a user's
|
|
30
|
+
// shell happens to have them set at invocation time.
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Frozen so third parties (or a poisoned import chain) cannot push a secret
|
|
33
|
+
// name onto the allowlist at runtime and leak it into the next buildChildEnv
|
|
34
|
+
// call. The whole point of the allowlist is defense-in-depth, so the exported
|
|
35
|
+
// surface is treated as immutable.
|
|
36
|
+
const ENV_ALLOWLIST = Object.freeze([
|
|
37
|
+
// POSIX basics
|
|
38
|
+
'PATH', 'HOME', 'USER', 'LOGNAME', 'SHELL', 'TERM', 'TMPDIR',
|
|
39
|
+
// Locale
|
|
40
|
+
'LANG', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES',
|
|
41
|
+
// Windows basics
|
|
42
|
+
'SYSTEMROOT', 'SYSTEMDRIVE', 'COMSPEC', 'USERPROFILE', 'LOCALAPPDATA',
|
|
43
|
+
'APPDATA', 'TEMP', 'TMP', 'USERNAME', 'PATHEXT', 'WINDIR',
|
|
44
|
+
'PROGRAMDATA', 'PROGRAMFILES', 'PROGRAMFILES(X86)', 'PROGRAMW6432',
|
|
45
|
+
'PROCESSOR_ARCHITECTURE', 'PROCESSOR_IDENTIFIER',
|
|
46
|
+
// Git Bash / MSYS
|
|
47
|
+
'MSYSTEM', 'MINGW_PREFIX', 'MINGW_CHOST',
|
|
48
|
+
// Proxies (needed for git/npm in corporate networks)
|
|
49
|
+
'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'ALL_PROXY',
|
|
50
|
+
'http_proxy', 'https_proxy', 'no_proxy',
|
|
51
|
+
// TLS CA bundles — consistent partner of the proxy vars above. Corporate
|
|
52
|
+
// networks with intercepting proxies need these or node/git fail TLS.
|
|
53
|
+
'NODE_EXTRA_CA_CERTS', 'SSL_CERT_FILE', 'SSL_CERT_DIR',
|
|
54
|
+
'GIT_SSL_CAINFO', 'GIT_SSL_CAPATH',
|
|
55
|
+
// Claude Code — setup validates `claude --version`, which needs this on Windows
|
|
56
|
+
'CLAUDE_CODE_GIT_BASH_PATH',
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
function buildChildEnv(ambient, extras = {}) {
|
|
60
|
+
// Reject non-object extras loudly. String/number/boolean extras silently
|
|
61
|
+
// spread wrong shapes (e.g. Object.assign({}, 'abc') → {0:'a',1:'b',2:'c'}),
|
|
62
|
+
// which produces a silently-wrong env instead of a caller-visible error.
|
|
63
|
+
if (extras !== undefined && extras !== null && (typeof extras !== 'object' || Array.isArray(extras))) {
|
|
64
|
+
throw new TypeError(`buildChildEnv: extras must be a plain object, got ${typeof extras}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const source = ambient || {};
|
|
68
|
+
const env = {};
|
|
69
|
+
for (const key of ENV_ALLOWLIST) {
|
|
70
|
+
if (source[key] !== undefined) {
|
|
71
|
+
env[key] = source[key];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Merge extras, but treat `undefined` as a no-op rather than overwriting the
|
|
76
|
+
// allowlisted value with an undefined. The source-side loop deliberately
|
|
77
|
+
// skips undefined keys; extras should follow the same rule for symmetry.
|
|
78
|
+
if (extras) {
|
|
79
|
+
for (const key of Object.keys(extras)) {
|
|
80
|
+
if (extras[key] !== undefined) {
|
|
81
|
+
env[key] = extras[key];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return env;
|
|
87
|
+
}
|
|
88
|
+
|
|
23
89
|
// Colors for terminal output
|
|
24
90
|
// NOTE: Intentionally duplicated from src/lib/colors.sh
|
|
25
91
|
// This is by design: cli.js runs standalone via npx before the rest of Vibe Forge
|
|
@@ -170,10 +236,7 @@ function runBashScript(scriptPath, args = []) {
|
|
|
170
236
|
const child = spawn(bashPath, [scriptPath, ...args], {
|
|
171
237
|
stdio: 'inherit',
|
|
172
238
|
cwd: process.cwd(),
|
|
173
|
-
env: {
|
|
174
|
-
...process.env,
|
|
175
|
-
CLAUDE_CODE_GIT_BASH_PATH: bashPath,
|
|
176
|
-
},
|
|
239
|
+
env: buildChildEnv(process.env, { CLAUDE_CODE_GIT_BASH_PATH: bashPath }),
|
|
177
240
|
});
|
|
178
241
|
|
|
179
242
|
child.on('close', (code) => {
|
|
@@ -209,18 +272,24 @@ async function initCommand() {
|
|
|
209
272
|
logSuccess('Prerequisites OK');
|
|
210
273
|
log('');
|
|
211
274
|
|
|
212
|
-
// Clone the repository
|
|
275
|
+
// Clone the repository. Uses spawnSync with an arg array rather than
|
|
276
|
+
// execSync with a template string so there is no shell-injection surface
|
|
277
|
+
// if REPO_URL or FORGE_DIR are ever derived from untrusted input.
|
|
213
278
|
logInfo(`Cloning Vibe Forge into ${FORGE_DIR}/...`);
|
|
214
|
-
|
|
215
|
-
|
|
279
|
+
const cloneResult = spawnSync(
|
|
280
|
+
'git',
|
|
281
|
+
['clone', '--depth', '1', REPO_URL, FORGE_DIR],
|
|
282
|
+
{
|
|
216
283
|
stdio: 'inherit',
|
|
217
284
|
cwd: process.cwd(),
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
285
|
+
env: buildChildEnv(process.env),
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
if (cloneResult.status !== 0) {
|
|
221
289
|
logError('Failed to clone repository');
|
|
222
290
|
process.exit(1);
|
|
223
291
|
}
|
|
292
|
+
logSuccess('Clone complete');
|
|
224
293
|
|
|
225
294
|
log('');
|
|
226
295
|
|
|
@@ -247,16 +316,26 @@ function validateAgentsConfig(forgeDir) {
|
|
|
247
316
|
const checkScript = path.join(forgeDir, 'bin', 'lib', 'check-aliases.js');
|
|
248
317
|
if (!fs.existsSync(checkScript)) return;
|
|
249
318
|
|
|
319
|
+
const agentsFile = path.join(forgeDir, 'config', 'agents.json');
|
|
320
|
+
const result = spawnSync('node', [checkScript, agentsFile], {
|
|
321
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
322
|
+
env: buildChildEnv(process.env),
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
if (result.status !== 0) {
|
|
326
|
+
logError('Agent alias collisions detected in config/agents.json');
|
|
327
|
+
const stderr = result.stderr ? result.stderr.toString().trim() : '';
|
|
328
|
+
logInfo(stderr || 'Run node src/lib/check-aliases.js for details');
|
|
329
|
+
logError('Fix collisions before using Vibe Forge.');
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
|
|
250
333
|
try {
|
|
251
|
-
const agentsFile = path.join(forgeDir, 'config', 'agents.json');
|
|
252
|
-
execSync(`node "${checkScript}" "${agentsFile}"`, { stdio: 'pipe' });
|
|
253
334
|
const config = JSON.parse(fs.readFileSync(agentsFile, 'utf8'));
|
|
254
335
|
const agentCount = Object.keys(config.agents || {}).length;
|
|
255
336
|
logSuccess(`Agent config valid (${agentCount} agents, no alias collisions)`);
|
|
256
|
-
} catch
|
|
257
|
-
logError('Agent
|
|
258
|
-
logInfo(err.stderr ? err.stderr.toString().trim() : 'Run node src/lib/check-aliases.js for details');
|
|
259
|
-
logError('Fix collisions before using Vibe Forge.');
|
|
337
|
+
} catch {
|
|
338
|
+
logError('Agent config validation passed, but agents.json could not be parsed.');
|
|
260
339
|
process.exit(1);
|
|
261
340
|
}
|
|
262
341
|
}
|
|
@@ -320,21 +399,29 @@ async function updateCommand() {
|
|
|
320
399
|
|
|
321
400
|
logInfo('Updating Vibe Forge...');
|
|
322
401
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
cwd: targetDir,
|
|
332
|
-
});
|
|
333
|
-
logSuccess('Update complete');
|
|
334
|
-
} catch {
|
|
402
|
+
const childEnv = buildChildEnv(process.env);
|
|
403
|
+
|
|
404
|
+
const fetchResult = spawnSync('git', ['fetch', 'origin'], {
|
|
405
|
+
stdio: 'inherit',
|
|
406
|
+
cwd: targetDir,
|
|
407
|
+
env: childEnv,
|
|
408
|
+
});
|
|
409
|
+
if (fetchResult.status !== 0) {
|
|
335
410
|
logError('Failed to update. Check your network connection or try deleting _vibe-forge and running init again.');
|
|
336
411
|
process.exit(1);
|
|
337
412
|
}
|
|
413
|
+
|
|
414
|
+
const resetResult = spawnSync('git', ['reset', '--hard', 'origin/main'], {
|
|
415
|
+
stdio: 'inherit',
|
|
416
|
+
cwd: targetDir,
|
|
417
|
+
env: childEnv,
|
|
418
|
+
});
|
|
419
|
+
if (resetResult.status !== 0) {
|
|
420
|
+
logError('Failed to update. Check your network connection or try deleting _vibe-forge and running init again.');
|
|
421
|
+
process.exit(1);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
logSuccess('Update complete');
|
|
338
425
|
}
|
|
339
426
|
|
|
340
427
|
// Main entry point
|
|
@@ -366,7 +453,14 @@ async function main() {
|
|
|
366
453
|
}
|
|
367
454
|
}
|
|
368
455
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
456
|
+
if (require.main === module) {
|
|
457
|
+
main().catch((err) => {
|
|
458
|
+
logError(err.message);
|
|
459
|
+
process.exit(1);
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
module.exports = {
|
|
464
|
+
buildChildEnv,
|
|
465
|
+
ENV_ALLOWLIST,
|
|
466
|
+
};
|