protovibe 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +244 -0
  3. package/dist/index.mjs +478 -0
  4. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 razorgojo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,244 @@
1
+ # ProtoVibe
2
+
3
+ > Vibecode your prototypes.
4
+
5
+ ProtoVibe is a CLI launchpad built on top of [Claude Code](https://claude.ai/code). It gives you a **structured, guided workflow** for turning a rough idea into a fully scoped, spec'd, and initialized project — before a single line of code is written.
6
+
7
+ Instead of opening Claude to a blank slate and figuring out what to ask, ProtoVibe walks you step-by-step through idea capture, deep requirements probing, architecture planning, and spec generation. Then it hands off to Claude Code with full context to build.
8
+
9
+ It makes **zero AI calls itself**. All intelligence comes from Claude Code, which ProtoVibe launches and drives through a 7-stage workflow prompt.
10
+
11
+ ---
12
+
13
+ ## Who is this for?
14
+
15
+ - Developers who want to **go from idea to structured specs** before building
16
+ - Anyone who finds it hard to **think through requirements** clearly on their own
17
+ - Builders who want Claude Code to have a **complete understanding of the project** before writing code
18
+ - Teams who want a **repeatable, consistent project kickoff** process
19
+
20
+ ---
21
+
22
+ ## Prerequisites
23
+
24
+ Before installing ProtoVibe, make sure you have:
25
+
26
+ - **Node.js v18+** — [nodejs.org](https://nodejs.org)
27
+ - **Claude Code** — install it with:
28
+ ```bash
29
+ npm install -g @anthropic-ai/claude-code
30
+ ```
31
+ Then run `claude` once and log in. ProtoVibe will check for credentials automatically.
32
+
33
+ ---
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ npm install -g protovibe
39
+ ```
40
+
41
+ Verify the install:
42
+
43
+ ```bash
44
+ protovibe --version
45
+ ```
46
+
47
+ ---
48
+
49
+ ## How to use it
50
+
51
+ Simply run:
52
+
53
+ ```bash
54
+ protovibe
55
+ ```
56
+
57
+ You will be asked two things:
58
+
59
+ 1. **Project name** — this becomes the folder name (letters, numbers, hyphens, underscores)
60
+ 2. **Where to create it** — browse and select a parent directory
61
+
62
+ That's all. ProtoVibe creates the project folder and launches Claude Code inside it. The 7-stage workflow starts automatically.
63
+
64
+ ---
65
+
66
+ ## What it looks like
67
+
68
+ When you run `protovibe`, you'll see this boot screen instantly:
69
+
70
+ ```
71
+ ██╗ ██╗██╗██████╗ ███████╗██████╗ ██████╗ ██████╗
72
+ ██║ ██║██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔═══██╗
73
+ ██║ ██║██║██████╔╝█████╗ ██████╔╝██████╔╝██║ ██║
74
+ ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██╔═══╝ ██╔══██╗██║ ██║
75
+ ╚████╔╝ ██║██████╔╝███████╗██║ ██║ ██║╚██████╔╝
76
+ ╚═══╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝
77
+ ```
78
+ *(rendered in a purple → blue gradient in your terminal)*
79
+
80
+ ```
81
+ ╭──────────────────────────────────────────╮
82
+ │ version 1.0.0 │
83
+ │ by razorgojo │
84
+ │ powered by Claude Code │
85
+ ├──────────────────────────────────────────┤
86
+ │ Vibecode your prototypes. │
87
+ ╰──────────────────────────────────────────╯
88
+ ```
89
+
90
+ The logo automatically switches to a compact version on narrower terminals (under 90 columns).
91
+
92
+ After the boot screen:
93
+
94
+ ```
95
+ ✔ Claude Code detected
96
+ ? Project name › my-app
97
+ ? Parent directory › /Users/you/projects
98
+
99
+ Launching Claude Code...
100
+ ```
101
+
102
+ Claude Code opens and the workflow begins immediately.
103
+
104
+ ---
105
+
106
+ ## The 7-Stage Workflow
107
+
108
+ Once Claude Code launches, it runs the ProtoVibe workflow automatically. Here's what each stage does:
109
+
110
+ ### Stage 0 — Mode Selection
111
+ Claude asks whether you want to start from scratch or work on an existing project.
112
+
113
+ ### Stage 0b — Existing Project Analysis *(if chosen)*
114
+ Paste a folder path. Claude reads the entire codebase, summarises what it does, the tech stack, and key features — then asks how you'd like to enhance it. The workflow ends here and Claude works normally from this point.
115
+
116
+ ### Stage 1 — Idea Capture
117
+ Claude asks: *"Describe the idea for your project."*
118
+ Just speak naturally. No format required.
119
+
120
+ ### Stage 2 — Deep Requirements Probing
121
+ Claude asks follow-up questions **one at a time** — covering users, features, platform, auth, data, integrations, and constraints. It keeps going until everything is fully clear. No question limit.
122
+
123
+ When done, it presents a structured summary and asks you to confirm before moving on.
124
+
125
+ ### Stage 3 — Architecture Options
126
+ Claude proposes **3 distinct architectural approaches**, each with:
127
+ - A full tech stack (frontend, backend, database, auth, hosting)
128
+ - How the system works end-to-end
129
+ - Tradeoffs — what it's best for and what it sacrifices
130
+ - One option marked as **Recommended** with a clear reason
131
+
132
+ ### Stage 4 — Option Confirmation
133
+ Pick one of the 3 options, or describe your own. If you go custom, Claude evaluates it against your requirements and flags any risks before proceeding.
134
+
135
+ ### Stage 5 — Specs File Creation
136
+ Claude writes `specs.md` in your project folder containing:
137
+ - Tech stack with justifications
138
+ - User flow (step-by-step)
139
+ - Feature list with priority labels: **P0** (MVP must-have), **P1** (important), **P2** (nice to have)
140
+ - Data model with entities and relationships
141
+ - Integration notes
142
+ - Constraints and non-functional requirements
143
+
144
+ ### Stage 6 — Initialization
145
+ Claude silently replaces the placeholder `CLAUDE.md` with a project-specific one using `/init`, so it has full context about your project going forward.
146
+
147
+ ### Stage 7 — Handoff
148
+ Workflow ends. Claude tells you: *"You can now go for building out the code."*
149
+ From here, Claude Code works normally on your project.
150
+
151
+ ---
152
+
153
+ ## Commands
154
+
155
+ ### `/takeover`
156
+ Exit the ProtoVibe workflow at any point. Run this inside Claude Code at any stage if you want to skip ahead and work directly.
157
+
158
+ Claude will summarise everything captured so far — idea, requirements, chosen architecture, files created — and then operate normally with no workflow constraints.
159
+
160
+ ---
161
+
162
+ ## What gets created in your project folder
163
+
164
+ ```
165
+ <your-project>/
166
+ ├── CLAUDE.md # Boots Claude into the /protovibe workflow
167
+ └── .claude/
168
+ └── commands/
169
+ ├── protovibe.md # The full 7-stage workflow instructions
170
+ └── takeover.md # The /takeover escape hatch definition
171
+ ```
172
+
173
+ After Stage 6, `CLAUDE.md` is replaced with a project-specific version generated by `/init`.
174
+ After Stage 5, `specs.md` is added to the root.
175
+
176
+ ---
177
+
178
+ ## Example session
179
+
180
+ ```
181
+ $ protovibe
182
+
183
+ # Boot screen renders instantly
184
+
185
+ ✔ Claude Code detected
186
+ ? Project name › client-portal
187
+ ? Parent directory › ~/projects
188
+
189
+ Launching Claude Code...
190
+
191
+ ────────────────────────────────────────
192
+ Claude Code v1.x — client-portal
193
+
194
+ Welcome to ProtoVibe. What would you like to do?
195
+ 1. Build from scratch
196
+ 2. Work on an existing project
197
+
198
+ > 1
199
+
200
+ Describe the idea for your project.
201
+
202
+ > A portal where my agency clients can view project status,
203
+ leave feedback, and approve deliverables without emailing me.
204
+
205
+ Who are the target users — your clients, your team, or both?
206
+
207
+ > Primarily clients. I'll have one admin view for myself.
208
+
209
+ What does "approve deliverables" mean exactly — sign off on files,
210
+ mark a task complete, something else?
211
+
212
+ > They should be able to view uploaded files and click Approve or
213
+ Request Changes, which notifies me.
214
+
215
+ ...
216
+ ```
217
+
218
+ Claude continues probing until requirements are complete, then presents architecture options and writes the specs.
219
+
220
+ ---
221
+
222
+ ## Development
223
+
224
+ ```bash
225
+ git clone https://github.com/SomSamantray/VibePro
226
+ cd VibePro
227
+ npm install
228
+ npm run build
229
+ node dist/index.mjs # run locally without global install
230
+ npm install -g . # install globally to test the protovibe command
231
+ ```
232
+
233
+ ### Scripts
234
+
235
+ | Command | Description |
236
+ |---------|-------------|
237
+ | `npm run build` | Compile TypeScript → `dist/` via tsup |
238
+ | `npm run dev` | Watch mode — rebuilds on every file change |
239
+
240
+ ---
241
+
242
+ ## License
243
+
244
+ MIT — see [LICENSE](./LICENSE)
package/dist/index.mjs ADDED
@@ -0,0 +1,478 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.tsx
4
+ import React5 from "react";
5
+ import { render } from "ink";
6
+
7
+ // src/cli.tsx
8
+ import React4, { useEffect, useState } from "react";
9
+ import { Box as Box3, Text as Text4, useApp } from "ink";
10
+
11
+ // src/components/Logo.tsx
12
+ import React2 from "react";
13
+ import { Box } from "ink";
14
+
15
+ // src/components/Gradient.tsx
16
+ import React from "react";
17
+ import { Text } from "ink";
18
+ function hexToRgb(hex) {
19
+ const h = hex.replace("#", "");
20
+ return [
21
+ parseInt(h.substring(0, 2), 16),
22
+ parseInt(h.substring(2, 4), 16),
23
+ parseInt(h.substring(4, 6), 16)
24
+ ];
25
+ }
26
+ function rgbToHex(r, g, b) {
27
+ return "#" + [r, g, b].map((v) => Math.round(v).toString(16).padStart(2, "0")).join("");
28
+ }
29
+ function interpolate(from, to, t) {
30
+ return rgbToHex(
31
+ from[0] + (to[0] - from[0]) * t,
32
+ from[1] + (to[1] - from[1]) * t,
33
+ from[2] + (to[2] - from[2]) * t
34
+ );
35
+ }
36
+ function Gradient({ text: text2, fromHex, toHex }) {
37
+ const from = hexToRgb(fromHex);
38
+ const to = hexToRgb(toHex);
39
+ const chars = text2.split("");
40
+ const len = chars.length - 1 || 1;
41
+ return /* @__PURE__ */ React.createElement(Text, null, chars.map((char, i) => /* @__PURE__ */ React.createElement(Text, { key: i, color: interpolate(from, to, i / len) }, char)));
42
+ }
43
+
44
+ // src/components/Logo.tsx
45
+ var LOGO_WIDE = [
46
+ "\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ",
47
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557",
48
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551",
49
+ "\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551",
50
+ " \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D",
51
+ " \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "
52
+ ];
53
+ var LOGO_COMPACT = [
54
+ "\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
55
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D",
56
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 ",
57
+ "\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D ",
58
+ " \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
59
+ " \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
60
+ ];
61
+ function Logo({ terminalWidth: terminalWidth2 }) {
62
+ const lines = terminalWidth2 >= 90 ? LOGO_WIDE : LOGO_COMPACT;
63
+ return /* @__PURE__ */ React2.createElement(Box, { flexDirection: "column", marginBottom: 1 }, lines.map((line, i) => /* @__PURE__ */ React2.createElement(Gradient, { key: i, text: line, fromHex: "#7B2FBE", toHex: "#3B82F6" })));
64
+ }
65
+
66
+ // src/components/InfoBox.tsx
67
+ import React3 from "react";
68
+ import { Box as Box2, Text as Text3 } from "ink";
69
+ var WIDTH = 42;
70
+ function InfoBox() {
71
+ const separator = "\u2500".repeat(WIDTH);
72
+ return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { color: "#3a1a6a" }, "\u256D" + "\u2500".repeat(WIDTH) + "\u256E"), /* @__PURE__ */ React3.createElement(Text3, { color: "#3a1a6a" }, "\u2502", /* @__PURE__ */ React3.createElement(Text3, { color: "#b39ddb" }, " version "), /* @__PURE__ */ React3.createElement(Text3, { color: "#ffffff" }, "1.0.0"), " ".repeat(WIDTH - 17), "\u2502"), /* @__PURE__ */ React3.createElement(Text3, { color: "#3a1a6a" }, "\u2502", /* @__PURE__ */ React3.createElement(Text3, { color: "#b39ddb" }, " by "), /* @__PURE__ */ React3.createElement(Text3, { color: "#ffffff" }, "razorgojo"), " ".repeat(WIDTH - 15), "\u2502"), /* @__PURE__ */ React3.createElement(Text3, { color: "#3a1a6a" }, "\u2502 ", /* @__PURE__ */ React3.createElement(Text3, { color: "#b39ddb" }, "powered by "), /* @__PURE__ */ React3.createElement(Gradient, { text: "Claude Code", fromHex: "#7B2FBE", toHex: "#3B82F6" }), " ".repeat(WIDTH - 25), "\u2502"), /* @__PURE__ */ React3.createElement(Text3, { color: "#3a1a6a" }, "\u251C" + separator + "\u2524"), /* @__PURE__ */ React3.createElement(Text3, { color: "#3a1a6a" }, "\u2502", /* @__PURE__ */ React3.createElement(Text3, { color: "#6d5a8a", italic: true }, " Vibecode your prototypes."), " ".repeat(WIDTH - 28), "\u2502"), /* @__PURE__ */ React3.createElement(Text3, { color: "#3a1a6a" }, "\u2570" + "\u2500".repeat(WIDTH) + "\u256F"));
73
+ }
74
+
75
+ // src/auth.ts
76
+ import { existsSync, readFileSync } from "fs";
77
+ import { join } from "path";
78
+ import { homedir } from "os";
79
+ function getClaudeCredentialsPath() {
80
+ return join(homedir(), ".claude", ".credentials.json");
81
+ }
82
+ function isAuthenticated() {
83
+ const credPath = getClaudeCredentialsPath();
84
+ if (!existsSync(credPath)) return false;
85
+ try {
86
+ const content = readFileSync(credPath, "utf-8").trim();
87
+ if (!content) return false;
88
+ const parsed = JSON.parse(content);
89
+ return Object.keys(parsed).length > 0;
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+
95
+ // src/spawn.ts
96
+ import { execSync, spawn } from "child_process";
97
+ function isClaudeInstalled() {
98
+ try {
99
+ const cmd = process.platform === "win32" ? "where claude" : "which claude";
100
+ execSync(cmd, { stdio: "ignore" });
101
+ return true;
102
+ } catch {
103
+ return false;
104
+ }
105
+ }
106
+ function spawnClaude(projectPath) {
107
+ const child = spawn("claude", [], {
108
+ stdio: "inherit",
109
+ cwd: projectPath,
110
+ shell: true
111
+ });
112
+ child.on("error", (err) => {
113
+ process.stderr.write(`Failed to start Claude Code: ${err.message}
114
+ `);
115
+ process.exit(1);
116
+ });
117
+ child.on("close", (code) => {
118
+ process.exit(code ?? 0);
119
+ });
120
+ }
121
+
122
+ // src/scaffold.ts
123
+ import { mkdirSync, writeFileSync, existsSync as existsSync2, readdirSync, statSync } from "fs";
124
+ import { join as join2, dirname } from "path";
125
+ import { homedir as homedir2 } from "os";
126
+ import * as clack from "@clack/prompts";
127
+
128
+ // src/templates/CLAUDE.md.ts
129
+ var CLAUDE_MD = `# CLAUDE.md
130
+
131
+ When you start, your first and only task is to run /protovibe.
132
+ Do not wait for user input. Do not do anything else first.
133
+
134
+ At any point during the workflow, the user can type /takeover to exit ProtoVibe and work directly in Claude Code with full context preserved.
135
+ `;
136
+
137
+ // src/templates/protovibe.md.ts
138
+ var PROTOVIBE_MD = `# ProtoVibe Workflow
139
+
140
+ You are running the ProtoVibe automated project setup workflow. Follow these stages strictly and in order. Do not skip stages. Do not do anything outside this workflow until it is complete \u2014 unless the user runs /takeover.
141
+
142
+ ---
143
+
144
+ ## Stage 0 \u2014 Mode Selection
145
+
146
+ Present the user with two options:
147
+
148
+ > "Welcome to ProtoVibe. What would you like to do?"
149
+ > 1. **Build from scratch** \u2014 start a new project
150
+ > 2. **Work on an existing project** \u2014 analyse and enhance an existing codebase
151
+
152
+ If the user selects **"Build from scratch"**: proceed to Stage 1.
153
+
154
+ If the user selects **"Work on an existing project"**: proceed to Stage 0b.
155
+
156
+ ---
157
+
158
+ ## Stage 0b \u2014 Existing Project Analysis
159
+
160
+ Ask the user:
161
+
162
+ > "What is the folder path to your project?"
163
+
164
+ Wait for them to provide a path. Accept any path string.
165
+
166
+ Once you have the path:
167
+ 1. Read and analyse all files inside that directory recursively (code files, config files, README, package.json, etc.)
168
+ 2. Build a complete understanding of the codebase \u2014 its purpose, architecture, and features
169
+ 3. Present a structured summary to the user in this format:
170
+
171
+ ---
172
+ **Project:** [inferred project name]
173
+ **What it does:** [1\u20132 sentence description of the project's purpose]
174
+ **Tech Stack:** [languages, frameworks, libraries detected]
175
+ **Key Features:**
176
+ [bulleted list \u2014 each feature with a one-line description of what it does]
177
+ **Structure:** [brief note on how the codebase is organised]
178
+ ---
179
+
180
+ After presenting the summary, exit the ProtoVibe workflow completely and ask:
181
+
182
+ > "How would you like to enhance it?"
183
+
184
+ From this point, respond naturally to whatever the user says. No more workflow stages. You are now working as Claude Code directly on their project.
185
+
186
+ ---
187
+
188
+ ## Stage 1 \u2014 Idea Capture
189
+
190
+ Ask exactly this:
191
+
192
+ > "Describe the idea for your project."
193
+
194
+ Wait for a free-text response. Accept anything. Do not proceed until you have an answer.
195
+
196
+ ---
197
+
198
+ ## Stage 2 \u2014 Deep Requirements Probing
199
+
200
+ Ask follow-up questions **one at a time**. Each question must be directly informed by all previous answers. Never ask about something already covered.
201
+
202
+ You must reach complete, unambiguous clarity on all of the following before moving on:
203
+ - **Who** are the target users? (be specific \u2014 not just "everyone")
204
+ - **What** does each core feature actually do? (behavior, not just names)
205
+ - **Platform** \u2014 web, mobile, desktop, CLI, or multiple?
206
+ - **Auth** \u2014 is user login required? If yes, what type?
207
+ - **Data** \u2014 what data is created, stored, read? Any real-time requirements?
208
+ - **Integrations** \u2014 any third-party services, APIs, or existing systems?
209
+ - **Constraints** \u2014 performance, offline support, team size, timeline, existing tech choices?
210
+
211
+ **There is no question limit.** Keep probing until you have zero unanswered questions. Do not summarize until everything is fully clear.
212
+
213
+ When you are confident nothing is ambiguous, present a complete structured summary:
214
+
215
+ ---
216
+ **Project:** [name]
217
+ **Users:** [specific description]
218
+ **Core Features:**
219
+ [bulleted list \u2014 each with a one-line description of its behavior]
220
+ **Platform:** [web / mobile / desktop / CLI]
221
+ **Auth:** [yes/no and type]
222
+ **Data & Storage:** [summary]
223
+ **Integrations:** [summary]
224
+ **Constraints:** [summary]
225
+ ---
226
+
227
+ Then ask: "Does this capture everything? Confirm to continue."
228
+
229
+ Do not proceed without explicit confirmation.
230
+
231
+ ---
232
+
233
+ ## Stage 3 \u2014 Architecture Options
234
+
235
+ Enter plan mode now using the /plan slash command.
236
+
237
+ Analyze the confirmed requirements carefully. Propose exactly **3 distinct architectural approaches** to build this project. For each option, provide:
238
+
239
+ 1. **A board-level description** of how the system works end-to-end
240
+ 2. **Full tech stack** (frontend, backend, database, hosting, auth, any key libraries)
241
+ 3. **Tradeoffs** \u2014 what this approach is best for, and what it sacrifices
242
+
243
+ After presenting all 3, clearly mark one as **Recommended** and explain specifically why it fits this user's requirements better than the others.
244
+
245
+ Then ask:
246
+
247
+ > "Which option would you like to go with? You can pick one of the above, or describe your own approach."
248
+
249
+ ---
250
+
251
+ ## Stage 4 \u2014 Option Confirmation
252
+
253
+ **If the user picks one of the 3 options:** confirm their choice and move to Stage 5.
254
+
255
+ **If the user describes a custom option** not on the list:
256
+ - Analyze the custom option against the confirmed requirements
257
+ - State clearly whether it is a good fit or not, and exactly why
258
+ - If it has risks or gaps, name them specifically
259
+ - Ask: "Given the above, would you like to proceed with your approach, or revisit the options?"
260
+ - Wait for their final confirmation before proceeding
261
+
262
+ ---
263
+
264
+ ## Stage 5 \u2014 Specs File Creation
265
+
266
+ Ask the user:
267
+
268
+ > "Ready for me to create the specs.md file?"
269
+
270
+ Wait for confirmation. Do not create the file without it.
271
+
272
+ On confirmation, write **specs.md** in the current working directory. It must contain:
273
+ - **Tech Stack** \u2014 chosen stack with a one-line justification for each major choice
274
+ - **User Flow** \u2014 step-by-step description of how a user moves through the app from first open to completing a core action
275
+ - **Feature List** \u2014 all features with priority labels (P0 = must have for MVP, P1 = important but not blocking, P2 = nice to have)
276
+ - **Data Model** \u2014 key entities, their fields, and relationships
277
+ - **Integration Notes** \u2014 any third-party services and how they connect
278
+ - **Constraints & NFRs** \u2014 performance targets, platform requirements, any hard constraints
279
+
280
+ After writing, tell the user:
281
+
282
+ > "specs.md has been created at \`[absolute path to specs.md]\`"
283
+
284
+ ---
285
+
286
+ ## Stage 6 \u2014 Initialization
287
+
288
+ Without asking the user, do the following in order:
289
+
290
+ 1. Delete the existing CLAUDE.md file in the current directory
291
+ 2. Run /init \u2014 this will analyze the project (including specs.md) and generate a new, project-aware CLAUDE.md
292
+
293
+ After /init completes, confirm:
294
+
295
+ > "CLAUDE.md \u2713 \u2014 your project is initialized."
296
+
297
+ Do not mention the deletion to the user. Do not ask permission. Just do it silently.
298
+
299
+ ---
300
+
301
+ ## Stage 7 \u2014 Handoff
302
+
303
+ Tell the user:
304
+
305
+ > "You can now go for building out the code."
306
+
307
+ Stop all automation. From this point forward, respond only to direct user requests. The ProtoVibe workflow is complete.
308
+
309
+ ---
310
+
311
+ ## /takeover \u2014 Emergency Exit (available at any stage)
312
+
313
+ If the user runs /takeover at any point during this workflow:
314
+
315
+ 1. Immediately stop all workflow automation
316
+ 2. Provide a brief context summary of what has been captured so far \u2014 idea, requirements confirmed, option chosen (if any), files created (if any)
317
+ 3. Tell the user: "ProtoVibe workflow exited. You're now working directly in Claude Code with full context."
318
+ 4. From this point, respond normally to all user requests with no workflow constraints
319
+ `;
320
+
321
+ // src/templates/takeover.md.ts
322
+ var TAKEOVER_MD = `# /takeover \u2014 Exit ProtoVibe Workflow
323
+
324
+ When this command is run:
325
+
326
+ 1. Immediately stop all ProtoVibe workflow automation, regardless of which stage you are currently in
327
+ 2. Provide a brief summary of everything captured so far:
328
+ - The project idea (if described)
329
+ - Requirements confirmed (if any)
330
+ - Architecture option chosen (if selected)
331
+ - Files created (specs.md, CLAUDE.md \u2014 if generated)
332
+ 3. Tell the user:
333
+
334
+ > "ProtoVibe workflow exited. You're now working directly in Claude Code with full context."
335
+
336
+ 4. From this point forward, respond normally to all user requests. No more workflow stages. No more automation. Just Claude Code.
337
+ `;
338
+
339
+ // src/scaffold.ts
340
+ function getSubdirectories(dirPath) {
341
+ try {
342
+ return readdirSync(dirPath).filter((name) => {
343
+ if (name.startsWith(".")) return false;
344
+ try {
345
+ return statSync(join2(dirPath, name)).isDirectory();
346
+ } catch {
347
+ return false;
348
+ }
349
+ }).sort();
350
+ } catch {
351
+ return [];
352
+ }
353
+ }
354
+ async function browseForDirectory() {
355
+ let currentPath = homedir2();
356
+ while (true) {
357
+ const subdirs = getSubdirectories(currentPath);
358
+ const isRoot = dirname(currentPath) === currentPath;
359
+ const options = [
360
+ { value: "__select__", label: `\u2713 Use this folder \u2014 ${currentPath}` },
361
+ ...!isRoot ? [{ value: "__up__", label: "\u2191 Go up" }] : [],
362
+ ...subdirs.map((dir) => ({ value: join2(currentPath, dir), label: `\u{1F4C1} ${dir}` }))
363
+ ];
364
+ const choice = await clack.select({
365
+ message: `\u{1F4C2} ${currentPath}`,
366
+ options
367
+ });
368
+ if (clack.isCancel(choice)) {
369
+ clack.cancel("Cancelled.");
370
+ process.exit(0);
371
+ }
372
+ if (choice === "__select__") {
373
+ return currentPath;
374
+ } else if (choice === "__up__") {
375
+ currentPath = dirname(currentPath);
376
+ } else {
377
+ currentPath = choice;
378
+ }
379
+ }
380
+ }
381
+ async function scaffoldProject() {
382
+ clack.intro("");
383
+ const projectName = await clack.text({
384
+ message: "Project name:",
385
+ validate(value) {
386
+ if (!value.trim()) return "Project name is required.";
387
+ if (/[^a-zA-Z0-9\-_]/.test(value)) return "Use only letters, numbers, hyphens, and underscores.";
388
+ }
389
+ });
390
+ if (clack.isCancel(projectName)) {
391
+ clack.cancel("Cancelled.");
392
+ process.exit(0);
393
+ }
394
+ clack.log.info("Select where to create your project:");
395
+ const parentDir = await browseForDirectory();
396
+ const targetDir = join2(parentDir, String(projectName));
397
+ if (existsSync2(targetDir)) {
398
+ clack.cancel(`Directory already exists: ${targetDir}`);
399
+ process.exit(1);
400
+ }
401
+ mkdirSync(join2(targetDir, ".claude", "commands"), { recursive: true });
402
+ writeFileSync(join2(targetDir, "CLAUDE.md"), CLAUDE_MD, "utf-8");
403
+ writeFileSync(join2(targetDir, ".claude", "commands", "protovibe.md"), PROTOVIBE_MD, "utf-8");
404
+ writeFileSync(join2(targetDir, ".claude", "commands", "takeover.md"), TAKEOVER_MD, "utf-8");
405
+ clack.outro(`\u2713 Project created at ${targetDir}`);
406
+ return targetDir;
407
+ }
408
+
409
+ // src/cli.tsx
410
+ import { confirm } from "@clack/prompts";
411
+ import { spawnSync } from "child_process";
412
+ function App({ terminalWidth: terminalWidth2 }) {
413
+ const { exit } = useApp();
414
+ const [stage, setStage] = useState("boot");
415
+ const [error, setError] = useState("");
416
+ useEffect(() => {
417
+ if (stage !== "boot") return;
418
+ const timer = setTimeout(() => setStage("auth-check"), 80);
419
+ return () => clearTimeout(timer);
420
+ }, [stage]);
421
+ useEffect(() => {
422
+ if (stage !== "auth-check") return;
423
+ if (isAuthenticated()) {
424
+ setStage("auth-done");
425
+ } else {
426
+ setStage("auth-prompt");
427
+ }
428
+ }, [stage]);
429
+ useEffect(() => {
430
+ if (stage !== "auth-prompt") return;
431
+ exit();
432
+ (async () => {
433
+ const shouldLogin = await confirm({
434
+ message: "This requires a Claude Code account. Do you want to log in now?"
435
+ });
436
+ if (!shouldLogin) {
437
+ process.stdout.write("\nLogin cancelled. Run protovibe again when ready.\n");
438
+ process.exit(0);
439
+ }
440
+ process.stdout.write(
441
+ "\nOpening Claude Code to log you in.\nOnce logged in, type /exit to return to ProtoVibe.\n\n"
442
+ );
443
+ spawnSync("claude", [], { stdio: "inherit", shell: true });
444
+ if (!isAuthenticated()) {
445
+ process.stderr.write("\n\u2717 Not logged in. Run protovibe again after logging in.\n");
446
+ process.exit(1);
447
+ }
448
+ setStage("auth-done");
449
+ })();
450
+ }, [stage]);
451
+ useEffect(() => {
452
+ if (stage !== "auth-done") return;
453
+ setStage("claude-check");
454
+ }, [stage]);
455
+ useEffect(() => {
456
+ if (stage !== "claude-check") return;
457
+ if (!isClaudeInstalled()) {
458
+ setError("Claude Code is not found. Please install it from claude.ai/code");
459
+ return;
460
+ }
461
+ setStage("scaffold");
462
+ }, [stage]);
463
+ useEffect(() => {
464
+ if (stage !== "scaffold") return;
465
+ exit();
466
+ scaffoldProject().then((projectPath) => {
467
+ spawnClaude(projectPath);
468
+ });
469
+ }, [stage]);
470
+ if (error) {
471
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingTop: 1 }, /* @__PURE__ */ React4.createElement(Logo, { terminalWidth: terminalWidth2 }), /* @__PURE__ */ React4.createElement(InfoBox, null), /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "red" }, "\u2717 ", error)));
472
+ }
473
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingTop: 1 }, /* @__PURE__ */ React4.createElement(Logo, { terminalWidth: terminalWidth2 }), /* @__PURE__ */ React4.createElement(InfoBox, null), (stage === "auth-done" || stage === "claude-check" || stage === "scaffold") && /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "#7B2FBE" }, "\u2713 "), /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, "Logged in to Claude Code")));
474
+ }
475
+
476
+ // src/index.tsx
477
+ var terminalWidth = process.stdout.columns ?? 80;
478
+ render(/* @__PURE__ */ React5.createElement(App, { terminalWidth }));
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "protovibe",
3
+ "version": "1.0.0",
4
+ "description": "A branded CLI platform layer on top of Claude Code",
5
+ "author": "razorgojo",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "claude",
9
+ "claude-code",
10
+ "cli",
11
+ "ai",
12
+ "scaffold",
13
+ "protovibe"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/SomSamantray/VibePro-CLI.git"
21
+ },
22
+ "homepage": "https://github.com/SomSamantray/VibePro-CLI#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/SomSamantray/VibePro-CLI/issues"
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "bin": {
30
+ "protovibe": "dist/index.mjs"
31
+ },
32
+ "main": "dist/index.mjs",
33
+ "type": "module",
34
+ "scripts": {
35
+ "build": "tsup",
36
+ "dev": "tsup --watch",
37
+ "prepublishOnly": "npm run build"
38
+ },
39
+ "dependencies": {
40
+ "@clack/prompts": "^1.1.0",
41
+ "chalk": "^5.6.2",
42
+ "ink": "^6.8.0",
43
+ "react": "^19.2.4"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^25.5.0",
47
+ "@types/react": "^19.2.14",
48
+ "tsup": "^8.5.1",
49
+ "typescript": "^5.9.3"
50
+ }
51
+ }