projecta-rrr 1.6.0 → 1.6.1

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/README.md CHANGED
@@ -219,6 +219,63 @@ If you choose a non-default provider, RRR asks for a reason and records it in De
219
219
 
220
220
  These are allowed but require explicit justification: Firebase, Supabase, Auth0, Vercel, PlanetScale.
221
221
 
222
+ ### MCP Auto-Setup
223
+
224
+ RRR includes an MCP registry that maps your selected providers to their MCP servers. After `/rrr:new-project` generates your `MVP_FEATURES.yml`:
225
+
226
+ ```bash
227
+ npm run mcp:setup
228
+ ```
229
+
230
+ This reads your feature selections and outputs the MCP configuration for Claude Code. Only MCPs you actually need get installed.
231
+
232
+ | Feature | MCP Server |
233
+ |---------|------------|
234
+ | Database (Neon) | `@neondatabase/mcp-server-neon` |
235
+ | Payments (Stripe) | `@stripe/mcp` |
236
+ | Analytics (PostHog) | `@anthropic/mcp-posthog` |
237
+ | Voice (Deepgram) | `@deepgram/mcp-server` |
238
+ | Browser (Browserbase) | `@anthropic/mcp-browserbase` |
239
+ | Sandbox (E2B) | `@e2b/mcp-server` |
240
+ | Storage (R2) | `@cloudflare/mcp-server-r2` |
241
+
242
+ **Always included:** Context7 (docs), GitHub, Filesystem, Sequential Thinking.
243
+
244
+ ### Pushpa Mode (Autopilot)
245
+
246
+ Run phases overnight while you sleep. Pushpa Mode is an unattended runner that plans and executes phases sequentially, skipping any that require human verification.
247
+
248
+ ```bash
249
+ bash scripts/pushpa-mode.sh
250
+ # or
251
+ npm run pushpa
252
+ ```
253
+
254
+ **What it does:**
255
+ 1. Preflights required API keys based on your `MVP_FEATURES.yml`
256
+ 2. Iterates through phases in order
257
+ 3. Plans any phase that doesn't have a plan yet
258
+ 4. Executes phases automatically
259
+ 5. **Skips** phases marked with `HITL_REQUIRED: true` (human verification needed)
260
+ 6. Generates a morning report at `.planning/PUSHPA_REPORT.md`
261
+
262
+ **Prerequisites:**
263
+ - Run `/rrr:new-project` first (project must be initialized)
264
+ - Set all required API keys (script will check and warn)
265
+ - Recommend enabling YOLO mode in `.planning/config.json`
266
+
267
+ **Where outputs live:**
268
+ - Report: `.planning/PUSHPA_REPORT.md`
269
+ - Logs: `.planning/logs/pushpa_*.log`
270
+
271
+ **HITL Convention:**
272
+ Plans that require human verification should include one of these markers:
273
+ - `HITL_REQUIRED: true` (canonical)
274
+ - `HUMAN_VERIFICATION_REQUIRED`
275
+ - `MANUAL_VERIFICATION`
276
+
277
+ Pushpa Mode will skip these phases and record them in the report for manual follow-up.
278
+
222
279
  ---
223
280
 
224
281
  ## How It Works
package/bin/install.js CHANGED
@@ -301,7 +301,26 @@ function finishInstall(settingsPath, settings, statuslineCommand, notifyCommand,
301
301
  writeSettings(settingsPath, settings);
302
302
 
303
303
  console.log(`
304
- ${green}Done!${reset} Launch Claude Code and run ${cyan}/rrr:help${reset}.
304
+ ${green}Done!${reset}
305
+
306
+ ${yellow}If you installed from inside Claude Code:${reset}
307
+ Type ${cyan}exit${reset} and restart ${cyan}claude${reset} so it reloads commands.
308
+
309
+ ${yellow}Pick your start command:${reset}
310
+
311
+ ${cyan}New/empty folder (greenfield)${reset}
312
+ /rrr:new-project
313
+ (bootstraps Next.js/TS baseline if folder is empty)
314
+
315
+ ${cyan}Existing repo (brownfield)${reset}
316
+ /rrr:new-project
317
+ (brownfield-safe; won't overwrite or restructure your repo)
318
+
319
+ ${cyan}RRR already initialized${reset}
320
+ /rrr:progress
321
+ (if .planning/STATE.md exists)
322
+
323
+ Run ${cyan}/rrr:help${reset} anytime to see all commands.
305
324
  `);
306
325
  }
307
326
 
@@ -19,6 +19,20 @@ Output ONLY the reference content below. Do NOT add:
19
19
 
20
20
  **RRR** creates hierarchical project plans optimized for solo agentic development with Claude Code. Built by [Projecta.ai](https://projecta.ai).
21
21
 
22
+ ## Getting Started
23
+
24
+ **After install/update:** If you installed from inside Claude Code, type `exit` and restart `claude` so it reloads commands.
25
+
26
+ **Pick your start command:**
27
+
28
+ | Scenario | Command |
29
+ |----------|---------|
30
+ | New/empty folder (greenfield) | `/rrr:new-project` — bootstraps Next.js/TS baseline if folder is empty |
31
+ | Existing repo (brownfield) | `/rrr:new-project` — brownfield-safe; won't overwrite your repo |
32
+ | RRR already initialized | `/rrr:progress` — if `.planning/STATE.md` exists |
33
+
34
+ **MVP Definition of Done at Projecta:** local demo runs + tests pass.
35
+
22
36
  ## Quick Start
23
37
 
24
38
  1. `/rrr:new-project` - Initialize project (includes research, requirements, roadmap)
@@ -381,6 +395,27 @@ Change anytime by editing `.planning/config.json`
381
395
 
382
396
  That's it! `/rrr:new-project` handles everything from bootstrap to roadmap.
383
397
 
398
+ **Overnight mode: Pushpa Mode**
399
+
400
+ Run phases unattended while you sleep:
401
+
402
+ ```
403
+ bash scripts/pushpa-mode.sh
404
+ # or
405
+ npm run pushpa
406
+ ```
407
+
408
+ Prerequisites:
409
+ 1. Run `/rrr:new-project` first
410
+ 2. Set all required API keys (based on your MVP_FEATURES.yml)
411
+ 3. Recommend enabling YOLO mode in config.json
412
+
413
+ Pushpa Mode will:
414
+ - Plan and execute phases sequentially
415
+ - Skip phases marked with `HITL_REQUIRED: true`
416
+ - Generate report at `.planning/PUSHPA_REPORT.md`
417
+ - Log everything to `.planning/logs/`
418
+
384
419
  **Bootstrap only (no planning):**
385
420
 
386
421
  ```
@@ -350,15 +350,17 @@ Use AskUserQuestion:
350
350
  - header: "Preset"
351
351
  - question: "Start with a use-case preset? This pre-configures capabilities."
352
352
  - options:
353
+ - "saas-dashboard (Recommended)" — SaaS with Clerk + Neon + optional Stripe (DEFAULT)
353
354
  - "landing-waitlist" — Landing page + email capture (no auth, no db)
354
- - "saas-dashboard" — SaaS with Clerk + Neon + optional Stripe
355
355
  - "api-admin" — API backend + admin panel (Neon, optional auth)
356
356
  - "voice-agent" — Voice AI agent (Deepgram + full agent stack)
357
- - "None" — Configure capabilities manually (Recommended for custom)
357
+ - "Custom" — Configure capabilities manually
358
358
 
359
359
  **If preset selected:** Load preset defaults, skip to Step 3 (confirm/override).
360
360
 
361
- **If "None":** Continue to Step 2.
361
+ **If "Custom":** Continue to Step 2.
362
+
363
+ **DEFAULT BEHAVIOR:** If user selects nothing or skips, assume `saas-dashboard` preset (Neon + Clerk + Render + optional Stripe).
362
364
 
363
365
  ### Step 2: Capability Questionnaire
364
366
 
@@ -496,6 +498,10 @@ Deviations: [count or "None"]
496
498
 
497
499
  File: .planning/MVP_FEATURES.yml
498
500
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
501
+
502
+ 💡 To configure MCP servers for your stack:
503
+ npm run mcp:setup
504
+ (Reads MVP_FEATURES.yml and installs required MCPs)
499
505
  ```
500
506
 
501
507
  Continue to Phase 3.
@@ -1272,6 +1278,16 @@ Present completion with next steps:
1272
1278
 
1273
1279
  <sub>`/clear` first → fresh context window</sub>
1274
1280
 
1281
+ ───────────────────────────────────────────────────────────────
1282
+
1283
+ ## 🔌 MCP Setup (Optional)
1284
+
1285
+ Configure Claude Code with MCP servers for your selected stack:
1286
+
1287
+ `npm run mcp:setup`
1288
+
1289
+ <sub>Reads MVP_FEATURES.yml and outputs MCP configuration</sub>
1290
+
1275
1291
  ───────────────────────────────────────────────────────────────
1276
1292
  ```
1277
1293
 
@@ -0,0 +1,128 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "description": "MCP server registry - maps providers to their Claude MCP installation commands",
4
+ "version": "1.0.0",
5
+
6
+ "servers": {
7
+ "neon": {
8
+ "name": "Neon MCP Server",
9
+ "description": "PostgreSQL database operations via Neon",
10
+ "command": "npx -y @neondatabase/mcp-server-neon",
11
+ "envRequired": ["NEON_API_KEY"],
12
+ "featureKeys": ["db:neon", "database"],
13
+ "docs": "https://neon.tech/docs/ai/mcp"
14
+ },
15
+
16
+ "stripe": {
17
+ "name": "Stripe MCP Server",
18
+ "description": "Payment processing and subscription management",
19
+ "command": "npx -y @stripe/mcp",
20
+ "envRequired": ["STRIPE_SECRET_KEY"],
21
+ "featureKeys": ["payments:stripe", "payments"],
22
+ "docs": "https://docs.stripe.com/mcp"
23
+ },
24
+
25
+ "posthog": {
26
+ "name": "PostHog MCP Server",
27
+ "description": "Product analytics and feature flags",
28
+ "command": "npx -y @anthropic/mcp-posthog",
29
+ "envRequired": ["POSTHOG_API_KEY", "POSTHOG_PROJECT_ID"],
30
+ "featureKeys": ["analytics:posthog", "analytics"],
31
+ "docs": "https://posthog.com/docs/mcp"
32
+ },
33
+
34
+ "deepgram": {
35
+ "name": "Deepgram MCP Server",
36
+ "description": "Voice-to-text and text-to-speech",
37
+ "command": "npx -y @deepgram/mcp-server",
38
+ "envRequired": ["DEEPGRAM_API_KEY"],
39
+ "featureKeys": ["voice:deepgram", "voice"],
40
+ "docs": "https://developers.deepgram.com/docs/mcp"
41
+ },
42
+
43
+ "browserbase": {
44
+ "name": "Browserbase MCP Server",
45
+ "description": "Headless browser automation",
46
+ "command": "npx -y @anthropic/mcp-browserbase",
47
+ "envRequired": ["BROWSERBASE_API_KEY", "BROWSERBASE_PROJECT_ID"],
48
+ "featureKeys": ["browserAutomation:browserbase", "browser"],
49
+ "docs": "https://docs.browserbase.com/mcp"
50
+ },
51
+
52
+ "e2b": {
53
+ "name": "E2B MCP Server",
54
+ "description": "Code execution sandbox",
55
+ "command": "npx -y @e2b/mcp-server",
56
+ "envRequired": ["E2B_API_KEY"],
57
+ "featureKeys": ["sandbox:e2b", "sandbox"],
58
+ "docs": "https://e2b.dev/docs/mcp"
59
+ },
60
+
61
+ "cloudflare-r2": {
62
+ "name": "Cloudflare R2 MCP Server",
63
+ "description": "S3-compatible object storage",
64
+ "command": "npx -y @cloudflare/mcp-server-r2",
65
+ "envRequired": ["CLOUDFLARE_ACCOUNT_ID", "R2_ACCESS_KEY_ID", "R2_SECRET_ACCESS_KEY"],
66
+ "featureKeys": ["objectStorage:r2", "storage"],
67
+ "docs": "https://developers.cloudflare.com/r2/mcp"
68
+ },
69
+
70
+ "context7": {
71
+ "name": "Context7 MCP Server",
72
+ "description": "Documentation lookup and library references",
73
+ "command": "npx -y @upstash/context7-mcp",
74
+ "envRequired": [],
75
+ "featureKeys": ["docs", "context"],
76
+ "docs": "https://context7.dev",
77
+ "alwaysInclude": true
78
+ },
79
+
80
+ "resend": {
81
+ "name": "Resend MCP Server",
82
+ "description": "Transactional email sending",
83
+ "command": "npx -y @resend/mcp-server",
84
+ "envRequired": ["RESEND_API_KEY"],
85
+ "featureKeys": ["email:resend", "email"],
86
+ "docs": "https://resend.com/docs/mcp"
87
+ },
88
+
89
+ "github": {
90
+ "name": "GitHub MCP Server",
91
+ "description": "GitHub repository operations",
92
+ "command": "npx -y @modelcontextprotocol/server-github",
93
+ "envRequired": ["GITHUB_PERSONAL_ACCESS_TOKEN"],
94
+ "featureKeys": ["github", "vcs"],
95
+ "docs": "https://modelcontextprotocol.io/docs/servers/github",
96
+ "alwaysInclude": true
97
+ },
98
+
99
+ "filesystem": {
100
+ "name": "Filesystem MCP Server",
101
+ "description": "Local filesystem operations",
102
+ "command": "npx -y @modelcontextprotocol/server-filesystem",
103
+ "envRequired": [],
104
+ "featureKeys": ["filesystem"],
105
+ "docs": "https://modelcontextprotocol.io/docs/servers/filesystem",
106
+ "alwaysInclude": true
107
+ },
108
+
109
+ "sequential-thinking": {
110
+ "name": "Sequential Thinking MCP Server",
111
+ "description": "Enhanced reasoning and chain-of-thought",
112
+ "command": "npx -y @modelcontextprotocol/server-sequential-thinking",
113
+ "envRequired": [],
114
+ "featureKeys": ["reasoning"],
115
+ "docs": "https://modelcontextprotocol.io/docs/servers/sequential-thinking",
116
+ "alwaysInclude": true
117
+ }
118
+ },
119
+
120
+ "presetMappings": {
121
+ "saas-dashboard": ["neon", "context7", "github", "filesystem", "sequential-thinking"],
122
+ "landing-waitlist": ["context7", "github", "filesystem", "sequential-thinking"],
123
+ "api-admin": ["neon", "context7", "github", "filesystem", "sequential-thinking"],
124
+ "voice-agent": ["neon", "deepgram", "e2b", "context7", "github", "filesystem", "sequential-thinking"]
125
+ },
126
+
127
+ "defaultServers": ["context7", "github", "filesystem", "sequential-thinking"]
128
+ }
package/package.json CHANGED
@@ -1,16 +1,23 @@
1
1
  {
2
2
  "name": "projecta-rrr",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "A meta-prompting, context engineering and spec-driven development system for Claude Code by Projecta.ai",
5
5
  "bin": {
6
6
  "projecta-rrr": "bin/install.js"
7
7
  },
8
+ "scripts": {
9
+ "mcp:setup": "bash scripts/mcp-setup.sh",
10
+ "pushpa": "bash scripts/pushpa-mode.sh"
11
+ },
8
12
  "files": [
9
13
  "bin",
10
14
  "commands",
11
15
  "rrr",
12
16
  "agents",
13
- "hooks"
17
+ "hooks",
18
+ "scripts",
19
+ "mcp.registry.json",
20
+ "projecta.defaults.json"
14
21
  ],
15
22
  "keywords": [
16
23
  "claude",
@@ -0,0 +1,32 @@
1
+ {
2
+ "framework": "nextjs-app-router",
3
+ "language": "typescript",
4
+ "packageManager": "npm",
5
+ "ui": {
6
+ "styling": "tailwind",
7
+ "componentSystem": "shadcn-ui"
8
+ },
9
+ "testing": {
10
+ "unit": "vitest",
11
+ "e2e": "playwright"
12
+ },
13
+ "preferredProviders": {
14
+ "db": ["neon"],
15
+ "auth": ["clerk", "neon-auth"],
16
+ "authDefault": "clerk",
17
+ "deploy": ["render"],
18
+ "payments": ["stripe"],
19
+ "objectStorage": ["r2"],
20
+ "analytics": ["posthog"],
21
+ "voice": ["deepgram"],
22
+ "agents": ["mastra"],
23
+ "agentAuth": ["authdev"],
24
+ "agentMail": ["agentmail"],
25
+ "sandbox": ["e2b"],
26
+ "browserAutomation": ["browserbase"]
27
+ },
28
+ "discouragedProviders": {
29
+ "list": ["firebase", "supabase", "auth0", "vercel", "planetscale"],
30
+ "note": "These providers are discouraged but allowed with explicit reason recorded in Deviation Notes"
31
+ }
32
+ }
@@ -1,7 +1,9 @@
1
- # SaaS Dashboard Preset
1
+ # SaaS Dashboard Preset (DEFAULT)
2
2
  # Auth + database required, payments optional
3
+ # This is the Projecta default preset - used when user skips selection
3
4
 
4
5
  name: saas-dashboard
6
+ default: true
5
7
  description: SaaS application with authentication, database, and optional payments
6
8
 
7
9
  stack:
@@ -70,6 +72,10 @@ database:
70
72
  - users (synced from Clerk)
71
73
  - user_data (application-specific)
72
74
 
75
+ # MCP servers auto-installed based on integrations
76
+ mcp_servers:
77
+ - neon # Required for database
78
+
73
79
  done_criteria:
74
80
  - User can sign up and sign in
75
81
  - Dashboard only accessible when authenticated
@@ -0,0 +1,224 @@
1
+ #!/bin/bash
2
+ #
3
+ # MCP Setup Script for Projecta RRR
4
+ # Reads MVP_FEATURES.yml and generates MCP server configuration
5
+ #
6
+
7
+ set -e
8
+
9
+ # Colors
10
+ RED='\033[0;31m'
11
+ GREEN='\033[0;32m'
12
+ YELLOW='\033[1;33m'
13
+ CYAN='\033[0;36m'
14
+ NC='\033[0m' # No Color
15
+
16
+ echo ""
17
+ echo -e "${CYAN}╔══════════════════════════════════════════╗${NC}"
18
+ echo -e "${CYAN}║ Projecta RRR - MCP Setup ║${NC}"
19
+ echo -e "${CYAN}╚══════════════════════════════════════════╝${NC}"
20
+ echo ""
21
+
22
+ # Find the RRR installation directory
23
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
24
+ RRR_DIR="$(dirname "$SCRIPT_DIR")"
25
+
26
+ # Check if we're in a project with .planning
27
+ PROJECT_DIR="$(pwd)"
28
+ FEATURES_FILE="$PROJECT_DIR/.planning/MVP_FEATURES.yml"
29
+ REGISTRY_FILE="$RRR_DIR/mcp.registry.json"
30
+
31
+ # Verify registry exists
32
+ if [ ! -f "$REGISTRY_FILE" ]; then
33
+ echo -e "${RED}Error: MCP registry not found at $REGISTRY_FILE${NC}"
34
+ exit 1
35
+ fi
36
+
37
+ # Determine which MCPs to include
38
+ MCP_SERVERS=()
39
+
40
+ # Always include default servers
41
+ DEFAULT_SERVERS=$(cat "$REGISTRY_FILE" | grep -A1000 '"defaultServers"' | grep -o '"[^"]*"' | tr -d '"' | head -10)
42
+ for server in $DEFAULT_SERVERS; do
43
+ if [ "$server" != "defaultServers" ] && [ "$server" != "[" ] && [ "$server" != "]" ]; then
44
+ MCP_SERVERS+=("$server")
45
+ fi
46
+ done
47
+
48
+ # Check if MVP_FEATURES.yml exists
49
+ if [ -f "$FEATURES_FILE" ]; then
50
+ echo -e "${GREEN}Found MVP_FEATURES.yml${NC}"
51
+ echo ""
52
+
53
+ # Extract preset if specified
54
+ PRESET=$(grep "^preset:" "$FEATURES_FILE" 2>/dev/null | cut -d: -f2 | tr -d ' ' || echo "")
55
+
56
+ if [ -n "$PRESET" ]; then
57
+ echo -e "Preset: ${CYAN}$PRESET${NC}"
58
+
59
+ # Get servers for this preset from registry
60
+ PRESET_SERVERS=$(cat "$REGISTRY_FILE" | grep -A10 "\"$PRESET\":" | grep -o '"[^"]*"' | tr -d '"' | grep -v "$PRESET" | head -10)
61
+ for server in $PRESET_SERVERS; do
62
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " ${server} " ]]; then
63
+ MCP_SERVERS+=("$server")
64
+ fi
65
+ done
66
+ fi
67
+
68
+ # Check for specific feature selections
69
+ # Database
70
+ if grep -q "db:" "$FEATURES_FILE" 2>/dev/null; then
71
+ DB=$(grep "db:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
72
+ if [ "$DB" = "neon" ]; then
73
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " neon " ]]; then
74
+ MCP_SERVERS+=("neon")
75
+ fi
76
+ fi
77
+ fi
78
+
79
+ # Payments
80
+ if grep -q "payments:" "$FEATURES_FILE" 2>/dev/null; then
81
+ PAYMENTS=$(grep "payments:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
82
+ if [ "$PAYMENTS" = "stripe" ]; then
83
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " stripe " ]]; then
84
+ MCP_SERVERS+=("stripe")
85
+ fi
86
+ fi
87
+ fi
88
+
89
+ # Voice
90
+ if grep -q "voice:" "$FEATURES_FILE" 2>/dev/null; then
91
+ VOICE=$(grep "voice:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
92
+ if [ "$VOICE" = "deepgram" ]; then
93
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " deepgram " ]]; then
94
+ MCP_SERVERS+=("deepgram")
95
+ fi
96
+ fi
97
+ fi
98
+
99
+ # Analytics
100
+ if grep -q "analytics:" "$FEATURES_FILE" 2>/dev/null; then
101
+ ANALYTICS=$(grep "analytics:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
102
+ if [ "$ANALYTICS" = "posthog" ]; then
103
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " posthog " ]]; then
104
+ MCP_SERVERS+=("posthog")
105
+ fi
106
+ fi
107
+ fi
108
+
109
+ # Browser automation
110
+ if grep -q "browserAutomation:" "$FEATURES_FILE" 2>/dev/null; then
111
+ BROWSER=$(grep "browserAutomation:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
112
+ if [ "$BROWSER" = "browserbase" ]; then
113
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " browserbase " ]]; then
114
+ MCP_SERVERS+=("browserbase")
115
+ fi
116
+ fi
117
+ fi
118
+
119
+ # Sandbox
120
+ if grep -q "sandbox:" "$FEATURES_FILE" 2>/dev/null; then
121
+ SANDBOX=$(grep "sandbox:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
122
+ if [ "$SANDBOX" = "e2b" ]; then
123
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " e2b " ]]; then
124
+ MCP_SERVERS+=("e2b")
125
+ fi
126
+ fi
127
+ fi
128
+
129
+ # Object storage
130
+ if grep -q "objectStorage:" "$FEATURES_FILE" 2>/dev/null; then
131
+ STORAGE=$(grep "objectStorage:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
132
+ if [ "$STORAGE" = "r2" ]; then
133
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " cloudflare-r2 " ]]; then
134
+ MCP_SERVERS+=("cloudflare-r2")
135
+ fi
136
+ fi
137
+ fi
138
+
139
+ # Email
140
+ if grep -q "email:" "$FEATURES_FILE" 2>/dev/null; then
141
+ EMAIL=$(grep "email:" "$FEATURES_FILE" | cut -d: -f2 | tr -d ' ')
142
+ if [ "$EMAIL" = "resend" ]; then
143
+ if [[ ! " ${MCP_SERVERS[*]} " =~ " resend " ]]; then
144
+ MCP_SERVERS+=("resend")
145
+ fi
146
+ fi
147
+ fi
148
+ else
149
+ echo -e "${YELLOW}No MVP_FEATURES.yml found - using SaaS default preset${NC}"
150
+ echo ""
151
+ # Add neon for SaaS default
152
+ MCP_SERVERS+=("neon")
153
+ fi
154
+
155
+ echo ""
156
+ echo -e "${GREEN}MCP Servers for your stack:${NC}"
157
+ echo "─────────────────────────────"
158
+
159
+ # Output the MCP configuration
160
+ for server in "${MCP_SERVERS[@]}"; do
161
+ # Get server details from registry
162
+ SERVER_NAME=$(cat "$REGISTRY_FILE" | grep -A5 "\"$server\":" | grep '"name"' | cut -d'"' -f4)
163
+ SERVER_CMD=$(cat "$REGISTRY_FILE" | grep -A5 "\"$server\":" | grep '"command"' | cut -d'"' -f4)
164
+
165
+ if [ -n "$SERVER_CMD" ]; then
166
+ echo -e " ${CYAN}$server${NC}: $SERVER_NAME"
167
+ echo -e " Command: ${YELLOW}$SERVER_CMD${NC}"
168
+ fi
169
+ done
170
+
171
+ echo ""
172
+ echo "─────────────────────────────"
173
+ echo ""
174
+ echo -e "${GREEN}To configure Claude Code with these MCPs:${NC}"
175
+ echo ""
176
+ echo "1. Open Claude Code settings:"
177
+ echo -e " ${CYAN}claude config${NC}"
178
+ echo ""
179
+ echo "2. Add MCP servers manually, or add to your ~/.claude/settings.json:"
180
+ echo ""
181
+
182
+ # Generate JSON snippet
183
+ echo -e "${YELLOW}{"
184
+ echo ' "mcpServers": {'
185
+
186
+ FIRST=true
187
+ for server in "${MCP_SERVERS[@]}"; do
188
+ SERVER_CMD=$(cat "$REGISTRY_FILE" | grep -A5 "\"$server\":" | grep '"command"' | cut -d'"' -f4)
189
+ if [ -n "$SERVER_CMD" ]; then
190
+ if [ "$FIRST" = true ]; then
191
+ FIRST=false
192
+ else
193
+ echo ","
194
+ fi
195
+ # Extract the package name from the npx command
196
+ PKG_NAME=$(echo "$SERVER_CMD" | sed 's/npx -y //')
197
+ echo -n " \"$server\": {"
198
+ echo -n "\"command\": \"npx\", \"args\": [\"-y\", \"$PKG_NAME\"]"
199
+ echo -n "}"
200
+ fi
201
+ done
202
+
203
+ echo ""
204
+ echo ' }'
205
+ echo -e "}${NC}"
206
+ echo ""
207
+
208
+ # List required environment variables
209
+ echo -e "${GREEN}Required environment variables:${NC}"
210
+ echo "─────────────────────────────"
211
+
212
+ for server in "${MCP_SERVERS[@]}"; do
213
+ ENV_VARS=$(cat "$REGISTRY_FILE" | grep -A10 "\"$server\":" | grep -A5 '"envRequired"' | grep -o '"[A-Z_]*"' | tr -d '"')
214
+ if [ -n "$ENV_VARS" ]; then
215
+ echo -e " ${CYAN}$server${NC}:"
216
+ for var in $ENV_VARS; do
217
+ echo " - $var"
218
+ done
219
+ fi
220
+ done
221
+
222
+ echo ""
223
+ echo -e "${GREEN}Done!${NC} Add the environment variables to your .env file."
224
+ echo ""
@@ -0,0 +1,639 @@
1
+ #!/bin/bash
2
+ #
3
+ # Pushpa Mode - Unattended Overnight Runner for RRR
4
+ # Runs plan+execute phases sequentially, skipping HITL-marked phases
5
+ #
6
+ # Usage: bash scripts/pushpa-mode.sh
7
+ #
8
+ # Requirements:
9
+ # - MVP_FEATURES.yml must exist (.planning/MVP_FEATURES.yml)
10
+ # - Required API keys must be set based on your feature selections
11
+ # - Claude Code must be installed and configured
12
+ #
13
+
14
+ set -euo pipefail
15
+
16
+ # ═══════════════════════════════════════════════════════════════════════════════
17
+ # Configuration
18
+ # ═══════════════════════════════════════════════════════════════════════════════
19
+
20
+ PLANNING_DIR=".planning"
21
+ PHASES_DIR="$PLANNING_DIR/phases"
22
+ LOGS_DIR="$PLANNING_DIR/logs"
23
+ FEATURES_FILE="$PLANNING_DIR/MVP_FEATURES.yml"
24
+ STATE_FILE="$PLANNING_DIR/STATE.md"
25
+ ROADMAP_FILE="$PLANNING_DIR/ROADMAP.md"
26
+ REPORT_FILE="$PLANNING_DIR/PUSHPA_REPORT.md"
27
+
28
+ # HITL markers that indicate human verification required
29
+ HITL_MARKERS=("HITL_REQUIRED: true" "HUMAN_VERIFICATION_REQUIRED" "MANUAL_VERIFICATION")
30
+
31
+ # Polling configuration
32
+ POLL_INTERVAL=10 # seconds between checks
33
+ MAX_POLL_ATTEMPTS=360 # 1 hour max wait (360 * 10s)
34
+
35
+ # Colors
36
+ RED='\033[0;31m'
37
+ GREEN='\033[0;32m'
38
+ YELLOW='\033[1;33m'
39
+ CYAN='\033[0;36m'
40
+ BOLD='\033[1m'
41
+ NC='\033[0m'
42
+
43
+ # ═══════════════════════════════════════════════════════════════════════════════
44
+ # Logging
45
+ # ═══════════════════════════════════════════════════════════════════════════════
46
+
47
+ LOG_FILE=""
48
+ START_TIME=""
49
+
50
+ setup_logging() {
51
+ mkdir -p "$LOGS_DIR"
52
+ START_TIME=$(date +%Y%m%d_%H%M%S)
53
+ LOG_FILE="$LOGS_DIR/pushpa_${START_TIME}.log"
54
+ touch "$LOG_FILE"
55
+ }
56
+
57
+ log() {
58
+ local level="$1"
59
+ local message="$2"
60
+ local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
61
+ echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
62
+
63
+ case "$level" in
64
+ INFO) echo -e "${CYAN}[$level]${NC} $message" ;;
65
+ OK) echo -e "${GREEN}[$level]${NC} $message" ;;
66
+ WARN) echo -e "${YELLOW}[$level]${NC} $message" ;;
67
+ ERROR) echo -e "${RED}[$level]${NC} $message" ;;
68
+ SKIP) echo -e "${YELLOW}[SKIP]${NC} $message" ;;
69
+ *) echo "[$level] $message" ;;
70
+ esac
71
+ }
72
+
73
+ # ═══════════════════════════════════════════════════════════════════════════════
74
+ # Banner
75
+ # ═══════════════════════════════════════════════════════════════════════════════
76
+
77
+ print_banner() {
78
+ echo ""
79
+ echo -e "${BOLD}${CYAN}"
80
+ echo "╔═══════════════════════════════════════════════════════════════╗"
81
+ echo "║ ║"
82
+ echo "║ ██████╗ ██╗ ██╗███████╗██╗ ██╗██████╗ █████╗ ║"
83
+ echo "║ ██╔══██╗██║ ██║██╔════╝██║ ██║██╔══██╗██╔══██╗ ║"
84
+ echo "║ ██████╔╝██║ ██║███████╗███████║██████╔╝███████║ ║"
85
+ echo "║ ██╔═══╝ ██║ ██║╚════██║██╔══██║██╔═══╝ ██╔══██║ ║"
86
+ echo "║ ██║ ╚██████╔╝███████║██║ ██║██║ ██║ ██║ ║"
87
+ echo "║ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ║"
88
+ echo "║ ║"
89
+ echo "║ RRR Overnight Autopilot Runner ║"
90
+ echo "║ ║"
91
+ echo "╚═══════════════════════════════════════════════════════════════╝"
92
+ echo -e "${NC}"
93
+ echo ""
94
+ }
95
+
96
+ # ═══════════════════════════════════════════════════════════════════════════════
97
+ # Preflight Checks
98
+ # ═══════════════════════════════════════════════════════════════════════════════
99
+
100
+ check_claude_installed() {
101
+ if ! command -v claude &> /dev/null; then
102
+ log ERROR "Claude Code CLI not found. Install it first: https://claude.ai/code"
103
+ exit 1
104
+ fi
105
+ log OK "Claude Code CLI found"
106
+ }
107
+
108
+ check_mvp_features() {
109
+ if [ ! -f "$FEATURES_FILE" ]; then
110
+ echo ""
111
+ echo -e "${RED}═══════════════════════════════════════════════════════════════${NC}"
112
+ echo -e "${RED} ERROR: MVP_FEATURES.yml not found${NC}"
113
+ echo -e "${RED}═══════════════════════════════════════════════════════════════${NC}"
114
+ echo ""
115
+ echo "Pushpa Mode requires a configured project with feature selections."
116
+ echo ""
117
+ echo "To get started:"
118
+ echo " 1. Run: /rrr:new-project"
119
+ echo " 2. Complete the questionnaire and capability selection"
120
+ echo " 3. Set required API keys (see below)"
121
+ echo " 4. Run: bash scripts/pushpa-mode.sh"
122
+ echo ""
123
+ exit 1
124
+ fi
125
+ log OK "MVP_FEATURES.yml found"
126
+ }
127
+
128
+ check_planning_exists() {
129
+ if [ ! -d "$PLANNING_DIR" ]; then
130
+ log WARN "No .planning directory found"
131
+ return 1
132
+ fi
133
+
134
+ if [ ! -f "$ROADMAP_FILE" ]; then
135
+ log WARN "No ROADMAP.md found"
136
+ return 1
137
+ fi
138
+
139
+ log OK "Planning directory and roadmap found"
140
+ return 0
141
+ }
142
+
143
+ # Check required environment variables based on MVP_FEATURES.yml
144
+ check_env_vars() {
145
+ local missing_vars=()
146
+ local features_content=$(cat "$FEATURES_FILE" 2>/dev/null || echo "")
147
+
148
+ log INFO "Checking required environment variables..."
149
+
150
+ # Neon (database)
151
+ if echo "$features_content" | grep -q "db:.*neon\|db: neon"; then
152
+ [ -z "${NEON_API_KEY:-}" ] && missing_vars+=("NEON_API_KEY")
153
+ [ -z "${DATABASE_URL:-}" ] && missing_vars+=("DATABASE_URL")
154
+ fi
155
+
156
+ # Clerk (auth)
157
+ if echo "$features_content" | grep -q "auth:.*clerk\|auth: clerk"; then
158
+ [ -z "${CLERK_SECRET_KEY:-}" ] && missing_vars+=("CLERK_SECRET_KEY")
159
+ [ -z "${NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:-}" ] && missing_vars+=("NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY")
160
+ fi
161
+
162
+ # Stripe (payments)
163
+ if echo "$features_content" | grep -q "payments:.*stripe\|payments: stripe"; then
164
+ [ -z "${STRIPE_SECRET_KEY:-}" ] && missing_vars+=("STRIPE_SECRET_KEY")
165
+ [ -z "${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:-}" ] && missing_vars+=("NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY (optional)")
166
+ fi
167
+
168
+ # Cloudflare R2 (storage)
169
+ if echo "$features_content" | grep -q "object_storage:.*r2\|objectStorage:.*r2"; then
170
+ [ -z "${CLOUDFLARE_ACCOUNT_ID:-}" ] && missing_vars+=("CLOUDFLARE_ACCOUNT_ID")
171
+ [ -z "${R2_ACCESS_KEY_ID:-}" ] && missing_vars+=("R2_ACCESS_KEY_ID")
172
+ [ -z "${R2_SECRET_ACCESS_KEY:-}" ] && missing_vars+=("R2_SECRET_ACCESS_KEY")
173
+ fi
174
+
175
+ # Deepgram (voice)
176
+ if echo "$features_content" | grep -q "voice:.*deepgram\|voice: deepgram"; then
177
+ [ -z "${DEEPGRAM_API_KEY:-}" ] && missing_vars+=("DEEPGRAM_API_KEY")
178
+ fi
179
+
180
+ # PostHog (analytics)
181
+ if echo "$features_content" | grep -q "analytics:.*posthog\|analytics: posthog"; then
182
+ [ -z "${NEXT_PUBLIC_POSTHOG_KEY:-}" ] && missing_vars+=("NEXT_PUBLIC_POSTHOG_KEY")
183
+ [ -z "${NEXT_PUBLIC_POSTHOG_HOST:-}" ] && missing_vars+=("NEXT_PUBLIC_POSTHOG_HOST")
184
+ fi
185
+
186
+ # E2B (sandbox)
187
+ if echo "$features_content" | grep -q "sandbox:.*e2b\|sandbox: e2b"; then
188
+ [ -z "${E2B_API_KEY:-}" ] && missing_vars+=("E2B_API_KEY")
189
+ fi
190
+
191
+ # Browserbase
192
+ if echo "$features_content" | grep -q "browser.*browserbase\|browserbase"; then
193
+ [ -z "${BROWSERBASE_API_KEY:-}" ] && missing_vars+=("BROWSERBASE_API_KEY")
194
+ [ -z "${BROWSERBASE_PROJECT_ID:-}" ] && missing_vars+=("BROWSERBASE_PROJECT_ID")
195
+ fi
196
+
197
+ if [ ${#missing_vars[@]} -gt 0 ]; then
198
+ echo ""
199
+ echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}"
200
+ echo -e "${YELLOW} WARNING: Missing environment variables${NC}"
201
+ echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}"
202
+ echo ""
203
+ echo "Based on your MVP_FEATURES.yml, these variables should be set:"
204
+ echo ""
205
+ for var in "${missing_vars[@]}"; do
206
+ echo -e " ${RED}✗${NC} $var"
207
+ done
208
+ echo ""
209
+ echo "Set them in your environment or .env file before running Pushpa Mode."
210
+ echo ""
211
+ echo "Example:"
212
+ echo " export NEON_API_KEY=your_key_here"
213
+ echo " # or"
214
+ echo " source .env"
215
+ echo ""
216
+
217
+ read -p "Continue anyway? (y/N) " -n 1 -r
218
+ echo
219
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
220
+ log ERROR "Aborted due to missing environment variables"
221
+ exit 1
222
+ fi
223
+ log WARN "Continuing with missing environment variables (user override)"
224
+ else
225
+ log OK "All required environment variables are set"
226
+ fi
227
+ }
228
+
229
+ # ═══════════════════════════════════════════════════════════════════════════════
230
+ # Phase Discovery
231
+ # ═══════════════════════════════════════════════════════════════════════════════
232
+
233
+ # Get list of phases from ROADMAP.md
234
+ get_phases() {
235
+ if [ ! -f "$ROADMAP_FILE" ]; then
236
+ echo ""
237
+ return
238
+ fi
239
+
240
+ # Extract phase numbers from ROADMAP.md
241
+ # Looks for patterns like "## Phase 1:" or "### Phase 1:" or "| 1 |"
242
+ grep -oE "Phase [0-9]+(\.[0-9]+)?" "$ROADMAP_FILE" 2>/dev/null | \
243
+ grep -oE "[0-9]+(\.[0-9]+)?" | \
244
+ sort -t. -k1,1n -k2,2n | \
245
+ uniq
246
+ }
247
+
248
+ # Check if phase has a plan
249
+ phase_has_plan() {
250
+ local phase="$1"
251
+ local phase_padded=$(printf "%02d" "${phase%%.*}")
252
+
253
+ # Look for plan files in the phase directory
254
+ local plan_files=$(find "$PHASES_DIR" -path "*/${phase_padded}*/*-PLAN.md" -type f 2>/dev/null | head -1)
255
+
256
+ if [ -n "$plan_files" ]; then
257
+ return 0
258
+ fi
259
+ return 1
260
+ }
261
+
262
+ # Get plan files for a phase
263
+ get_phase_plans() {
264
+ local phase="$1"
265
+ local phase_padded=$(printf "%02d" "${phase%%.*}")
266
+
267
+ find "$PHASES_DIR" -path "*/${phase_padded}*/*-PLAN.md" -type f 2>/dev/null | sort
268
+ }
269
+
270
+ # Check if phase plan contains HITL marker
271
+ phase_requires_hitl() {
272
+ local phase="$1"
273
+ local plan_files=$(get_phase_plans "$phase")
274
+
275
+ if [ -z "$plan_files" ]; then
276
+ return 1 # No plan, no HITL
277
+ fi
278
+
279
+ for plan_file in $plan_files; do
280
+ for marker in "${HITL_MARKERS[@]}"; do
281
+ if grep -q "$marker" "$plan_file" 2>/dev/null; then
282
+ log INFO "Found HITL marker '$marker' in $plan_file"
283
+ return 0
284
+ fi
285
+ done
286
+ done
287
+
288
+ return 1
289
+ }
290
+
291
+ # Check if milestone is complete
292
+ is_milestone_complete() {
293
+ local completion_markers=("MVP COMPLETE" "MILESTONE COMPLETE" "ALL PHASES COMPLETE" "100%")
294
+
295
+ for marker in "${completion_markers[@]}"; do
296
+ if grep -qi "$marker" "$STATE_FILE" 2>/dev/null; then
297
+ return 0
298
+ fi
299
+ if grep -qi "$marker" "$ROADMAP_FILE" 2>/dev/null; then
300
+ return 0
301
+ fi
302
+ done
303
+
304
+ return 1
305
+ }
306
+
307
+ # ═══════════════════════════════════════════════════════════════════════════════
308
+ # Execution
309
+ # ═══════════════════════════════════════════════════════════════════════════════
310
+
311
+ # Run a Claude Code command
312
+ run_claude_command() {
313
+ local command="$1"
314
+ local description="$2"
315
+
316
+ log INFO "Running: $command"
317
+ log INFO "Description: $description"
318
+
319
+ # Run claude with the command, capturing output
320
+ local output_file="$LOGS_DIR/claude_${START_TIME}_$(date +%s).log"
321
+
322
+ if claude -p "$command" >> "$output_file" 2>&1; then
323
+ log OK "Command completed successfully"
324
+ return 0
325
+ else
326
+ log ERROR "Command failed. Check $output_file for details"
327
+ return 1
328
+ fi
329
+ }
330
+
331
+ # Wait for plan files to appear
332
+ wait_for_plan() {
333
+ local phase="$1"
334
+ local attempts=0
335
+
336
+ log INFO "Waiting for plan files for Phase $phase..."
337
+
338
+ while [ $attempts -lt $MAX_POLL_ATTEMPTS ]; do
339
+ if phase_has_plan "$phase"; then
340
+ log OK "Plan files found for Phase $phase"
341
+ return 0
342
+ fi
343
+
344
+ sleep $POLL_INTERVAL
345
+ ((attempts++))
346
+
347
+ if [ $((attempts % 6)) -eq 0 ]; then
348
+ log INFO "Still waiting for plan files... (${attempts}/${MAX_POLL_ATTEMPTS})"
349
+ fi
350
+ done
351
+
352
+ log ERROR "Timeout waiting for plan files for Phase $phase"
353
+ return 1
354
+ }
355
+
356
+ # Plan a phase
357
+ plan_phase() {
358
+ local phase="$1"
359
+
360
+ log INFO "Planning Phase $phase..."
361
+
362
+ if ! run_claude_command "/rrr:plan-phase $phase" "Create plan for Phase $phase"; then
363
+ log ERROR "Failed to plan Phase $phase"
364
+ return 1
365
+ fi
366
+
367
+ # Wait for plan files to appear
368
+ if ! wait_for_plan "$phase"; then
369
+ return 1
370
+ fi
371
+
372
+ return 0
373
+ }
374
+
375
+ # Execute a phase
376
+ execute_phase() {
377
+ local phase="$1"
378
+
379
+ log INFO "Executing Phase $phase..."
380
+
381
+ if ! run_claude_command "/rrr:execute-phase $phase" "Execute Phase $phase"; then
382
+ log ERROR "Failed to execute Phase $phase"
383
+ return 1
384
+ fi
385
+
386
+ log OK "Phase $phase execution complete"
387
+ return 0
388
+ }
389
+
390
+ # ═══════════════════════════════════════════════════════════════════════════════
391
+ # Report Generation
392
+ # ═══════════════════════════════════════════════════════════════════════════════
393
+
394
+ # Phase tracking arrays
395
+ declare -a PLANNED_PHASES=()
396
+ declare -a EXECUTED_PHASES=()
397
+ declare -a SKIPPED_PHASES=()
398
+ declare -a FAILED_PHASES=()
399
+
400
+ init_report() {
401
+ cat > "$REPORT_FILE" << EOF
402
+ # Pushpa Mode Report
403
+
404
+ **Started:** $(date '+%Y-%m-%d %H:%M:%S')
405
+ **Log File:** $LOG_FILE
406
+
407
+ ---
408
+
409
+ ## Summary
410
+
411
+ | Metric | Count |
412
+ |--------|-------|
413
+ | Phases Planned | — |
414
+ | Phases Executed | — |
415
+ | Phases Skipped (HITL) | — |
416
+ | Phases Failed | — |
417
+
418
+ ---
419
+
420
+ ## Phase Details
421
+
422
+ EOF
423
+ }
424
+
425
+ update_report() {
426
+ local end_time=$(date '+%Y-%m-%d %H:%M:%S')
427
+
428
+ cat > "$REPORT_FILE" << EOF
429
+ # Pushpa Mode Report
430
+
431
+ **Started:** $(date -d "@$(($(date +%s) - SECONDS))" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "$(date '+%Y-%m-%d %H:%M:%S')")
432
+ **Completed:** $end_time
433
+ **Duration:** $((SECONDS / 60)) minutes
434
+ **Log File:** $LOG_FILE
435
+
436
+ ---
437
+
438
+ ## Summary
439
+
440
+ | Metric | Count |
441
+ |--------|-------|
442
+ | Phases Planned | ${#PLANNED_PHASES[@]} |
443
+ | Phases Executed | ${#EXECUTED_PHASES[@]} |
444
+ | Phases Skipped (HITL) | ${#SKIPPED_PHASES[@]} |
445
+ | Phases Failed | ${#FAILED_PHASES[@]} |
446
+
447
+ ---
448
+
449
+ ## Phase Details
450
+
451
+ EOF
452
+
453
+ if [ ${#EXECUTED_PHASES[@]} -gt 0 ]; then
454
+ echo "### Executed" >> "$REPORT_FILE"
455
+ for phase in "${EXECUTED_PHASES[@]}"; do
456
+ echo "- Phase $phase ✓" >> "$REPORT_FILE"
457
+ done
458
+ echo "" >> "$REPORT_FILE"
459
+ fi
460
+
461
+ if [ ${#SKIPPED_PHASES[@]} -gt 0 ]; then
462
+ echo "### Skipped (HITL Required)" >> "$REPORT_FILE"
463
+ echo "" >> "$REPORT_FILE"
464
+ echo "These phases require human verification and were skipped:" >> "$REPORT_FILE"
465
+ echo "" >> "$REPORT_FILE"
466
+ for phase in "${SKIPPED_PHASES[@]}"; do
467
+ echo "- Phase $phase — **HITL_REQUIRED**" >> "$REPORT_FILE"
468
+ done
469
+ echo "" >> "$REPORT_FILE"
470
+ echo "> Run these phases manually with \`/rrr:execute-phase N\` after verification." >> "$REPORT_FILE"
471
+ echo "" >> "$REPORT_FILE"
472
+ fi
473
+
474
+ if [ ${#FAILED_PHASES[@]} -gt 0 ]; then
475
+ echo "### Failed" >> "$REPORT_FILE"
476
+ echo "" >> "$REPORT_FILE"
477
+ echo "These phases encountered errors:" >> "$REPORT_FILE"
478
+ echo "" >> "$REPORT_FILE"
479
+ for phase in "${FAILED_PHASES[@]}"; do
480
+ echo "- Phase $phase ✗" >> "$REPORT_FILE"
481
+ done
482
+ echo "" >> "$REPORT_FILE"
483
+ echo "> Check logs at \`$LOGS_DIR/\` for details." >> "$REPORT_FILE"
484
+ echo "" >> "$REPORT_FILE"
485
+ fi
486
+
487
+ echo "---" >> "$REPORT_FILE"
488
+ echo "" >> "$REPORT_FILE"
489
+ echo "*Generated by Pushpa Mode*" >> "$REPORT_FILE"
490
+ }
491
+
492
+ # ═══════════════════════════════════════════════════════════════════════════════
493
+ # Main
494
+ # ═══════════════════════════════════════════════════════════════════════════════
495
+
496
+ main() {
497
+ print_banner
498
+ setup_logging
499
+
500
+ log INFO "Pushpa Mode starting..."
501
+ log INFO "Working directory: $(pwd)"
502
+
503
+ # Preflight checks
504
+ echo -e "${BOLD}Preflight Checks${NC}"
505
+ echo "─────────────────────────────────────────"
506
+
507
+ check_claude_installed
508
+ check_mvp_features
509
+ check_env_vars
510
+
511
+ # Check if planning exists, run new-project if not
512
+ if ! check_planning_exists; then
513
+ log WARN "Planning not initialized. Running /rrr:new-project..."
514
+ echo ""
515
+ echo -e "${YELLOW}Planning not found. Please run /rrr:new-project first.${NC}"
516
+ echo ""
517
+ echo "Pushpa Mode requires:"
518
+ echo " 1. .planning/ROADMAP.md (phases defined)"
519
+ echo " 2. .planning/MVP_FEATURES.yml (feature selections)"
520
+ echo ""
521
+ echo "Run /rrr:new-project interactively to set up your project,"
522
+ echo "then run Pushpa Mode again."
523
+ exit 1
524
+ fi
525
+
526
+ echo ""
527
+ echo -e "${GREEN}All preflight checks passed!${NC}"
528
+ echo ""
529
+
530
+ # Check if already complete
531
+ if is_milestone_complete; then
532
+ log OK "Milestone is already complete!"
533
+ echo -e "${GREEN}Milestone is already complete. Nothing to do.${NC}"
534
+ exit 0
535
+ fi
536
+
537
+ # Get phases
538
+ local phases=$(get_phases)
539
+
540
+ if [ -z "$phases" ]; then
541
+ log ERROR "No phases found in ROADMAP.md"
542
+ exit 1
543
+ fi
544
+
545
+ log INFO "Found phases: $(echo $phases | tr '\n' ' ')"
546
+
547
+ # Initialize report
548
+ init_report
549
+
550
+ echo -e "${BOLD}Starting Execution${NC}"
551
+ echo "─────────────────────────────────────────"
552
+ echo ""
553
+
554
+ # Process each phase
555
+ for phase in $phases; do
556
+ echo ""
557
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
558
+ echo -e "${CYAN} Phase $phase${NC}"
559
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
560
+
561
+ # Check if plan exists
562
+ if ! phase_has_plan "$phase"; then
563
+ log INFO "No plan found for Phase $phase, creating..."
564
+
565
+ if plan_phase "$phase"; then
566
+ PLANNED_PHASES+=("$phase")
567
+ else
568
+ log ERROR "Failed to create plan for Phase $phase"
569
+ FAILED_PHASES+=("$phase")
570
+ continue
571
+ fi
572
+ else
573
+ log OK "Plan already exists for Phase $phase"
574
+ fi
575
+
576
+ # Check for HITL marker
577
+ if phase_requires_hitl "$phase"; then
578
+ log SKIP "Phase $phase requires human verification (HITL_REQUIRED)"
579
+ echo -e "${YELLOW} ⚠ Skipping - Human verification required${NC}"
580
+ SKIPPED_PHASES+=("$phase")
581
+ continue
582
+ fi
583
+
584
+ # Execute phase
585
+ if execute_phase "$phase"; then
586
+ EXECUTED_PHASES+=("$phase")
587
+ echo -e "${GREEN} ✓ Phase $phase complete${NC}"
588
+ else
589
+ FAILED_PHASES+=("$phase")
590
+ echo -e "${RED} ✗ Phase $phase failed${NC}"
591
+ fi
592
+
593
+ # Check if milestone became complete
594
+ if is_milestone_complete; then
595
+ log OK "Milestone complete!"
596
+ break
597
+ fi
598
+ done
599
+
600
+ # Generate final report
601
+ update_report
602
+
603
+ echo ""
604
+ echo -e "${BOLD}═══════════════════════════════════════════════════════════════${NC}"
605
+ echo -e "${BOLD} Pushpa Mode Complete${NC}"
606
+ echo -e "${BOLD}═══════════════════════════════════════════════════════════════${NC}"
607
+ echo ""
608
+ echo "Results:"
609
+ echo " Planned: ${#PLANNED_PHASES[@]} phases"
610
+ echo " Executed: ${#EXECUTED_PHASES[@]} phases"
611
+ echo " Skipped: ${#SKIPPED_PHASES[@]} phases (HITL required)"
612
+ echo " Failed: ${#FAILED_PHASES[@]} phases"
613
+ echo ""
614
+ echo "Report: $REPORT_FILE"
615
+ echo "Logs: $LOG_FILE"
616
+ echo ""
617
+
618
+ if [ ${#SKIPPED_PHASES[@]} -gt 0 ]; then
619
+ echo -e "${YELLOW}HITL phases to complete manually:${NC}"
620
+ for phase in "${SKIPPED_PHASES[@]}"; do
621
+ echo " /rrr:execute-phase $phase"
622
+ done
623
+ echo ""
624
+ fi
625
+
626
+ if [ ${#FAILED_PHASES[@]} -gt 0 ]; then
627
+ echo -e "${RED}Failed phases to investigate:${NC}"
628
+ for phase in "${FAILED_PHASES[@]}"; do
629
+ echo " Phase $phase"
630
+ done
631
+ echo ""
632
+ exit 1
633
+ fi
634
+
635
+ log OK "Pushpa Mode finished successfully"
636
+ }
637
+
638
+ # Run main
639
+ main "$@"