ship-create 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/create.mjs CHANGED
@@ -5,18 +5,23 @@
5
5
  * Why no npm dependencies: the audience is non-developers. Requiring
6
6
  * extra packages before the very first command, or an API key before
7
7
  * anything works, is exactly the kind of friction that loses beginners.
8
- * This script uses only Node.js built-ins (fs, path, readline) and pastes
9
- * a ready prompt for the user to run in whichever AI chat tool they
10
- * already use — no API key, no extra setup.
8
+ * This script uses only Node.js built-ins (fs, path, readline,
9
+ * child_process) no API key, no extra setup.
11
10
  *
12
11
  * Usage:
13
12
  * npx ship-create
14
13
  *
15
- * All templates this script needs (the starter-kit app, PROJECT.md,
16
- * HUMAN_FLOW.md, PROMPTS.md, product-type templates, and the agent rule
17
- * files) are bundled inside this package's own templates/ folder — nothing
18
- * is read from outside this package, so it works standalone via npx,
19
- * with no git clone required.
14
+ * All templates (starter-kit app, agent rule files, Claude skill) are
15
+ * bundled inside this package's own templates/ folder nothing is read
16
+ * from outside, so it works standalone via npx.
17
+ *
18
+ * What changed from v1.3.1 → v1.4.0:
19
+ * - Removed the AI-tool picker (no longer needed)
20
+ * - Added 4 idea questions so PROJECT.md + HUMAN_FLOW.md are pre-filled
21
+ * with real content (no [bracket placeholders] in the core sections)
22
+ * - Runs `npm install` automatically so the project is ready to open
23
+ * - End message tells the user exactly how to start building in their
24
+ * AI coding tool — no intermediate manual steps
20
25
  */
21
26
 
22
27
  import fs from "node:fs";
@@ -24,28 +29,76 @@ import path from "node:path";
24
29
  import readline from "node:readline";
25
30
  import { stdin as input, stdout as output } from "node:process";
26
31
  import { fileURLToPath } from "node:url";
32
+ import { spawnSync } from "node:child_process";
27
33
 
28
34
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
29
35
  const TEMPLATES_DIR = path.join(__dirname, "templates");
30
36
 
31
37
  const PRODUCT_TYPES = [
32
- { key: "SAAS", label: "SaaS product", file: "SAAS_TEMPLATE.md" },
33
- { key: "CRM", label: "CRM system", file: "CRM_TEMPLATE.md" },
34
- { key: "MEMBERSHIP", label: "Membership site", file: "MEMBERSHIP_TEMPLATE.md" },
35
- { key: "LEADGEN", label: "Lead generation website", file: "LEADGEN_TEMPLATE.md" },
36
- { key: "DIRECTORY", label: "Directory website", file: "DIRECTORY_TEMPLATE.md" },
37
- { key: "DASHBOARD", label: "Dashboard / internal analytics", file: "DASHBOARD_TEMPLATE.md" },
38
- { key: "INTERNAL_TOOL", label: "Internal tool", file: "INTERNAL_TOOL_TEMPLATE.md" },
39
- { key: "MARKETPLACE", label: "Marketplace", file: "MARKETPLACE_TEMPLATE.md" },
38
+ { key: "SAAS", label: "SaaS product", file: "SAAS_TEMPLATE.md" },
39
+ { key: "CRM", label: "CRM system", file: "CRM_TEMPLATE.md" },
40
+ { key: "MEMBERSHIP", label: "Membership site", file: "MEMBERSHIP_TEMPLATE.md" },
41
+ { key: "LEADGEN", label: "Lead generation website", file: "LEADGEN_TEMPLATE.md" },
42
+ { key: "DIRECTORY", label: "Directory website", file: "DIRECTORY_TEMPLATE.md" },
43
+ { key: "DASHBOARD", label: "Dashboard / internal analytics", file: "DASHBOARD_TEMPLATE.md" },
44
+ { key: "INTERNAL_TOOL", label: "Internal tool", file: "INTERNAL_TOOL_TEMPLATE.md" },
45
+ { key: "MARKETPLACE", label: "Marketplace", file: "MARKETPLACE_TEMPLATE.md" },
40
46
  ];
41
47
 
42
- const AI_TOOLS = [
43
- { key: "ChatGPT", note: "Paste the prompt below into a new chat (or set up a Custom GPT for repeated use)." },
44
- { key: "Claude", note: "Paste into a new chat, or set up a Claude Project with your docs as Project knowledge." },
45
- { key: "Gemini", note: "Paste into a new chat, or set up a Gemini Gem for repeated use." },
46
- { key: "Cursor", note: "Open PROJECT.md in the editor and reference it with @PROJECT.md instead of pasting. Use Ask/Chat mode, not Agent mode, for this step." },
47
- { key: "Windsurf", note: "Same idea as Cursor reference PROJECT.md directly via the editor's file context instead of pasting." },
48
- ];
48
+ // Pre-seeded journey stages per product type so HUMAN_FLOW.md has real
49
+ // content the moment the project is created.
50
+ const JOURNEY_SEEDS = {
51
+ SAAS: {
52
+ discovery: "Googles a pain they have, or sees a post about the tool from someone they follow",
53
+ firstUse: "Signs up, sets up their workspace, completes onboarding in under 5 minutes",
54
+ habitual: "Comes back daily — it's now the default tool for this part of their work",
55
+ advocacy: "Invites teammates, shares a screenshot publicly, or recommends it unprompted",
56
+ },
57
+ CRM: {
58
+ discovery: "Frustrated with spreadsheets or outgrowing their current CRM",
59
+ firstUse: "Imports contacts, creates their first deal, moves it through the pipeline",
60
+ habitual: "Logs every interaction, tracks deals from lead to close without thinking about it",
61
+ advocacy: "Gets their whole sales team on it, pushes for it in team meetings",
62
+ },
63
+ MEMBERSHIP: {
64
+ discovery: "Finds the creator/brand through content, a recommendation, or an ad",
65
+ firstUse: "Signs up for free or paid tier, accesses their first piece of content",
66
+ habitual: "Returns regularly for new content and engages in the community",
67
+ advocacy: "Refers friends, shares content, or upgrades to a higher tier",
68
+ },
69
+ LEADGEN: {
70
+ discovery: "Finds the page via search, ad, or referral while actively looking for a solution",
71
+ firstUse: "Reads the page, fills out a form or books a call",
72
+ habitual: "Becomes a paying customer after the follow-up sequence",
73
+ advocacy: "Refers others in their network who need the same service",
74
+ },
75
+ DIRECTORY: {
76
+ discovery: "Searches for a specific provider or category in the niche",
77
+ firstUse: "Browses listings, contacts or books a provider directly",
78
+ habitual: "Returns when they need another provider, or to leave a review",
79
+ advocacy: "Shares the directory with their network when someone asks for a recommendation",
80
+ },
81
+ DASHBOARD: {
82
+ discovery: "Team lead or ops person is tired of copy-pasting data into spreadsheets",
83
+ firstUse: "Connects data sources, sees the first charts populate automatically",
84
+ habitual: "Checks the dashboard every morning as the first thing in their routine",
85
+ advocacy: "Shares views with stakeholders, adds more team members as viewers",
86
+ },
87
+ INTERNAL_TOOL: {
88
+ discovery: "Team identifies a manual, repetitive process that's slowing them down",
89
+ firstUse: "First team member completes the core task in the tool, faster than before",
90
+ habitual: "Whole team uses it as the default — the old process is gone",
91
+ advocacy: "Other teams ask if they can get a version for their workflow too",
92
+ },
93
+ MARKETPLACE: {
94
+ discovery: "Buyer searches for a product or service and lands on a listing",
95
+ firstUse: "Browses listings, makes first purchase or sends first inquiry",
96
+ habitual: "Returns to buy again, or becomes a repeat seller",
97
+ advocacy: "Refers buyers and sellers in their network",
98
+ },
99
+ };
100
+
101
+ // ─── helpers ────────────────────────────────────────────────────────────────
49
102
 
50
103
  function toKebabCase(str) {
51
104
  return str
@@ -55,11 +108,9 @@ function toKebabCase(str) {
55
108
  .replace(/(^-|-$)/g, "") || "my-product";
56
109
  }
57
110
 
58
- // Reading lines via the readline interface's async iterator (rather than
59
- // the higher-level `question()` API) avoids a Node.js quirk where piped /
60
- // redirected (non-TTY) stdin can stop delivering buffered lines after the
61
- // first question() call resolves. The async-iterator pattern reliably
62
- // delivers every line regardless of how stdin is supplied.
111
+ // Use the readline async iterator rather than the `question()` API to avoid
112
+ // a Node.js quirk where piped / non-TTY stdin stops delivering buffered
113
+ // lines after the first question() call resolves.
63
114
  function makeLineReader(rl) {
64
115
  const it = rl[Symbol.asyncIterator]();
65
116
  return async function nextLine(promptText) {
@@ -101,31 +152,203 @@ function copyRecursiveExcluding(src, dest, excludeNames) {
101
152
  }
102
153
  }
103
154
 
104
- function fillProjectTemplate(rawTemplate, projectName, productTypeLabel) {
105
- return rawTemplate
106
- .replace(
107
- "## 1. Product Vision",
108
- `## 1. Product Vision\n\n> Project: **${projectName}** — a ${productTypeLabel}. Replace the rest of this section with your own one-paragraph vision.`
109
- )
110
- .replace(
111
- "## 4. Target Audience",
112
- `## 4. Target Audience\n\n> Product type: ${productTypeLabel}. See \`docs/${productTypeLabel}\`'s matching template file in this project for a starter feature checklist.`
113
- );
155
+ // ─── doc builders ───────────────────────────────────────────────────────────
156
+
157
+ function buildProjectMd(projectName, productTypeLabel, { targetUser, problem, valueProp, idea }) {
158
+ return `# PROJECT.md
159
+
160
+ **Phase:** S — Structure
161
+ **Purpose:** Single source of truth for *what* you're building and *why*. Every AI build prompt should point here instead of re-explaining the product from scratch.
162
+
163
+ ---
164
+
165
+ ## 1. Product Vision
166
+
167
+ ${projectName} is a ${productTypeLabel.toLowerCase()} that helps **${targetUser}** ${valueProp}.
168
+
169
+ > *Expand this into a fuller paragraph before moving to HUMAN_FLOW.md — what does this product become in 2 years if it succeeds?*
170
+
171
+ ---
172
+
173
+ ## 2. Problem Statement
174
+
175
+ - **Who has this problem:** ${targetUser}
176
+ - **What is the problem, specifically:** ${problem}
177
+ - **How do they solve it today** (workarounds, competitors, spreadsheets, manual labor): [fill in]
178
+ - **Why do existing solutions fail them:** [fill in]
179
+ - **Cost of the problem** (time, money, missed opportunity, stress — quantify if possible): [fill in]
180
+
181
+ ---
182
+
183
+ ## 3. Opportunity
184
+
185
+ - **Why now** (market shift, new tech, behavior change, AI cost drop, etc.): [fill in]
186
+ - **Market size / addressable audience** (rough is fine): [fill in]
187
+ - **Unfair advantage** (your access, audience, data, speed, niche knowledge): [fill in]
188
+ - **Why AI makes this newly buildable by you, solo or with a small team:** [fill in]
189
+
190
+ ---
191
+
192
+ ## 4. Target Audience
193
+
194
+ | Attribute | Description |
195
+ |---|---|
196
+ | Primary segment | ${targetUser} |
197
+ | Secondary segment | [fill in] |
198
+ | Demographics / firmographics | [fill in] |
199
+ | Where they hang out (channels) | [fill in] |
200
+ | What they currently pay for adjacent solutions | [fill in] |
201
+ | Buying trigger (what makes them search for this *today*) | [fill in] |
202
+
203
+ ---
204
+
205
+ ## 5. User Personas
206
+
207
+ ### Persona 1: Primary User
208
+ - **Goal:** ${valueProp}
209
+ - **Frustration:** ${problem}
210
+ - **Tech comfort level:** [fill in]
211
+ - **Quote that sounds like them:** "[fill in]"
212
+ - **What "success" looks like for them in this product:** [fill in]
213
+
214
+ ---
215
+
216
+ ## 6. MVP Scope
217
+
218
+ > Smallest version that delivers real value to Persona 1. 3–5 features max.
219
+
220
+ - [fill in]
221
+ - [fill in]
222
+ - [fill in]
223
+
224
+ ### Out of scope for MVP
225
+ - [fill in — things you explicitly will NOT build yet]
226
+
227
+ ---
228
+
229
+ ## 7. Success Metrics
230
+
231
+ | Metric | Target (Month 1) | Target (Month 3) |
232
+ |---|---|---|
233
+ | [fill in] | | |
234
+
235
+ ---
236
+
237
+ ## 8. Revenue Model
238
+
239
+ - **Pricing model:** [subscription / one-time / freemium / marketplace fee / etc.]
240
+ - **Price point:** [fill in]
241
+ - **Revenue goal (Month 3):** [fill in]
242
+
243
+ ---
244
+
245
+ ## 9. Original Idea (keep for reference)
246
+
247
+ > *Your words from when you scaffolded this project.*
248
+
249
+ ${idea || "(not provided)"}
250
+ `;
114
251
  }
115
252
 
253
+ function buildHumanFlowMd(projectName, productType, { targetUser, problem, valueProp }) {
254
+ const seed = JOURNEY_SEEDS[productType.key] || JOURNEY_SEEDS.SAAS;
255
+
256
+ return `# HUMAN_FLOW.md
257
+
258
+ **Phase:** H — Human Flow
259
+ **Purpose:** Maps how a real ${targetUser} moves through ${projectName} — screen by screen, decision by decision — before any code is written. Skipping this is the #1 reason AI-generated apps feel disjointed.
260
+
261
+ ---
262
+
263
+ ## 1. User Journey
264
+
265
+ | Stage | What the user is trying to do | Where they are emotionally |
266
+ |---|---|---|
267
+ | Discovery | ${seed.discovery} | Curious but skeptical — "does this actually work?" |
268
+ | First use | ${seed.firstUse} | Evaluating — will bounce at the first confusing screen |
269
+ | Habitual use | ${seed.habitual} | Comfortable and trusting |
270
+ | Advocacy | ${seed.advocacy} | Proud to recommend it |
271
+
272
+ ---
273
+
274
+ ## 2. User Flow — Core Task
275
+
276
+ > Map the step-by-step sequence for the most important action a user takes. Fill in the blanks.
277
+
278
+ \`\`\`
279
+ [Entry point] → [Step 1: action] → [Step 2: action] → [Decision point?]
280
+ ├─ Yes → [Step 3a]
281
+ └─ No → [Step 3b]
282
+ → [Outcome / success state]
283
+ \`\`\`
284
+
285
+ - **Flow name:** [e.g. "New user signs up and reaches first value"]
286
+ - **Entry point(s):** [homepage CTA / email link / referral / etc.]
287
+ - **Steps to reach value:** [count them — every extra step is a drop-off risk]
288
+ - **Exit points:** [where can they bail, and is that OK?]
289
+
290
+ ---
291
+
292
+ ## 3. Core Screens
293
+
294
+ > One section per screen. Every screen needs a happy path and at least one error/empty state before it gets built.
295
+
296
+ ### Screen 1: [Name — e.g. Landing page]
297
+ - **Purpose:** [what does the user do or decide here?]
298
+ - **Happy path:** [what happens when everything works]
299
+ - **Empty state:** [what the user sees on first visit with no data]
300
+ - **Error state:** [what happens if something goes wrong]
301
+
302
+ ### Screen 2: [Name — e.g. Dashboard]
303
+ - **Purpose:**
304
+ - **Happy path:**
305
+ - **Empty state:**
306
+ - **Error state:**
307
+
308
+ ### Screen 3: [Name — e.g. Settings]
309
+ - **Purpose:**
310
+ - **Happy path:**
311
+ - **Empty state:**
312
+ - **Error state:**
313
+
314
+ > Add more screens until every route in Section 4 has a matching entry here.
315
+
316
+ ---
317
+
318
+ ## 4. Information Architecture
319
+
320
+ | Route | Screen name | Who can access |
321
+ |---|---|---|
322
+ | / | Landing / Home | Public |
323
+ | /dashboard | Main app view | Logged-in user |
324
+ | /settings | Account settings | Logged-in user |
325
+ | [fill in] | | |
326
+
327
+ ---
328
+
329
+ ## 5. Key UX Decisions
330
+
331
+ > Record decisions that affect the whole product so the AI agent doesn't re-litigate them each session.
332
+
333
+ - Auth method: [magic link / OAuth / password — pick one]
334
+ - Mobile-first or desktop-first: [fill in]
335
+ - [fill in any other non-obvious decisions]
336
+ `;
337
+ }
338
+
339
+ // ─── main ───────────────────────────────────────────────────────────────────
340
+
116
341
  async function main() {
117
342
  const rl = readline.createInterface({ input, terminal: false });
118
343
  const nextLine = makeLineReader(rl);
119
344
 
120
345
  console.log("===========================================");
121
- console.log(" SHIP CLI — start a new project, the SHIP way");
122
- console.log("===========================================");
123
- console.log(
124
- "\nNo API key needed. This just sets up your files and gives you a\nready-to-paste prompt for ChatGPT, Claude, Gemini, Cursor, or Windsurf.\n"
125
- );
346
+ console.log(" SHIP CLI — scaffold your project in 60 s");
347
+ console.log("===========================================\n");
126
348
 
127
- const projectNameRaw = await ask(nextLine, "What's your project called?", "My Product");
128
- const projectSlug = toKebabCase(projectNameRaw);
349
+ // ── 1. Core questions ──────────────────────────────────────────────────
350
+ const projectNameRaw = await ask(nextLine, "Project name?", "My Product");
351
+ const projectSlug = toKebabCase(projectNameRaw);
129
352
 
130
353
  const productType = await pickFromList(
131
354
  nextLine,
@@ -134,178 +357,130 @@ async function main() {
134
357
  (t) => t.label
135
358
  );
136
359
 
137
- const aiTool = await pickFromList(
360
+ // ── 2. Idea questions (fills the docs without needing a separate AI step)
361
+ console.log("\n── About your idea ─────────────────────────");
362
+ const idea = await ask(
138
363
  nextLine,
139
- "Which AI tool will you mainly use?",
140
- AI_TOOLS,
141
- (t) => t.key
364
+ "Describe it in 1-3 sentences (who it's for and what it does)",
365
+ ""
142
366
  );
367
+ const targetUser = await ask(
368
+ nextLine,
369
+ "Who is your primary user? (e.g. 'freelance designers', 'gym owners')",
370
+ "small business owners"
371
+ );
372
+ const problem = await ask(
373
+ nextLine,
374
+ "What is the #1 problem they face today?",
375
+ ""
376
+ );
377
+ const valueProp = await ask(
378
+ nextLine,
379
+ "What makes them say 'I need this'? (the aha moment)",
380
+ ""
381
+ );
382
+
383
+ // Close readline before any child processes touch stdin
384
+ rl.close();
143
385
 
144
- // The project is created inside whatever folder you currently have open
145
- // (process.cwd()) — not inside the SHIP Method OS repo itself. This way
146
- // it behaves like `npx create-next-app`: open any empty folder, run the
147
- // command, get your project right there.
386
+ // ── 3. Guard: don't overwrite an existing folder ───────────────────────
148
387
  const outDir = path.join(process.cwd(), projectSlug);
149
388
  if (fs.existsSync(outDir)) {
150
- console.log(`\n A folder already exists at ./${projectSlug} — pick a different name and run again.`);
151
- rl.close();
152
- return;
389
+ console.log(`\n Folder ./${projectSlug} already exists — pick a different name and run again.`);
390
+ process.exit(1);
153
391
  }
154
392
 
155
- console.log(`\nCreating ./${projectSlug} ...`);
393
+ console.log(`\nScaffolding ./${projectSlug} ...`);
156
394
 
157
- // 1. Copy the working app shell (sale/member/backoffice UI on mock data)
158
- // from this package's bundled templates — nothing is read from outside
159
- // this package.
160
395
  const starterKitSrc = path.join(TEMPLATES_DIR, "starter-kit");
161
396
  if (!fs.existsSync(starterKitSrc) || !fs.existsSync(path.join(TEMPLATES_DIR, "docs"))) {
162
- console.log(
163
- "\nThis package's bundled templates are missing or incomplete.\n" +
164
- "Try reinstalling: npx ship-create@latest\n"
165
- );
166
- rl.close();
397
+ console.log("\nBundled templates missing. Try: npx ship-create@latest\n");
167
398
  process.exit(1);
168
399
  }
400
+
401
+ // ── 4. Copy app shell ──────────────────────────────────────────────────
169
402
  copyRecursiveExcluding(
170
403
  starterKitSrc,
171
404
  outDir,
172
- new Set([
173
- "node_modules",
174
- ".next",
175
- "package-lock.json",
176
- "next-env.d.ts",
177
- "tsconfig.tsbuildinfo",
178
- ])
405
+ new Set(["node_modules", ".next", "package-lock.json", "next-env.d.ts", "tsconfig.tsbuildinfo"])
179
406
  );
180
407
 
181
- // 2. Copy the agent rule files so any coding tool enforces the SHIP order from day one.
408
+ // ── 5. Copy agent rule files (CLAUDE.md, AGENTS.md, .cursorrules, etc.)
182
409
  for (const ruleFile of ["AGENTS.md", "CLAUDE.md", ".cursorrules", ".windsurfrules"]) {
183
410
  const src = path.join(TEMPLATES_DIR, ruleFile);
184
- if (fs.existsSync(src)) {
185
- fs.copyFileSync(src, path.join(outDir, ruleFile));
186
- }
411
+ if (fs.existsSync(src)) fs.copyFileSync(src, path.join(outDir, ruleFile));
187
412
  }
188
413
 
189
- // 2b. Copy the Claude Code skill (.claude/skills/ship-method/SKILL.md) so
190
- // Claude Code can explicitly invoke the SHIP workflow as a skill, not
191
- // just follow it as a passive rules file.
414
+ // ── 6. Copy Claude Code skill so agents can invoke it as a skill ───────
192
415
  const claudeSkillSrc = path.join(TEMPLATES_DIR, ".claude");
193
416
  if (fs.existsSync(claudeSkillSrc)) {
194
417
  copyRecursiveExcluding(claudeSkillSrc, path.join(outDir, ".claude"), new Set());
195
418
  }
196
419
 
197
- // 3. Create a docs/ folder with a pre-filled PROJECT.md and the matching product-type template.
420
+ // ── 7. Write pre-filled docs (no bracket placeholders in core sections)
198
421
  const docsDir = path.join(outDir, "docs");
199
422
  fs.mkdirSync(docsDir, { recursive: true });
200
423
 
201
- const projectMdSrc = path.join(TEMPLATES_DIR, "docs", "PROJECT.md");
202
- const rawProjectMd = fs.readFileSync(projectMdSrc, "utf8");
203
424
  fs.writeFileSync(
204
425
  path.join(docsDir, "PROJECT.md"),
205
- fillProjectTemplate(rawProjectMd, projectNameRaw, productType.label)
426
+ buildProjectMd(projectNameRaw, productType.label, { targetUser, problem, valueProp, idea })
427
+ );
428
+
429
+ fs.writeFileSync(
430
+ path.join(docsDir, "HUMAN_FLOW.md"),
431
+ buildHumanFlowMd(projectNameRaw, productType, { targetUser, problem, valueProp })
206
432
  );
207
433
 
434
+ // Product-type feature checklist
208
435
  const templateSrc = path.join(TEMPLATES_DIR, "docs", "product-types", productType.file);
209
436
  if (fs.existsSync(templateSrc)) {
210
437
  fs.copyFileSync(templateSrc, path.join(docsDir, productType.file));
211
438
  }
212
439
 
213
- const humanFlowSrc = path.join(TEMPLATES_DIR, "docs", "HUMAN_FLOW.md");
214
- if (fs.existsSync(humanFlowSrc)) {
215
- fs.copyFileSync(humanFlowSrc, path.join(docsDir, "HUMAN_FLOW.md"));
216
- }
217
-
218
- // Copy the full prompt chain too, so this project is self-contained.
440
+ // Full prompt chain (Stages 3-6) for users who want it
219
441
  const promptsSrc = path.join(TEMPLATES_DIR, "docs", "PROMPTS.md");
220
442
  if (fs.existsSync(promptsSrc)) {
221
443
  fs.copyFileSync(promptsSrc, path.join(docsDir, "PROMPTS.md"));
222
444
  }
223
445
 
224
- // 4. Build the ready-to-paste Stage 1 prompt (Idea -> Product Spec), pre-loaded with the template.
225
- const prompt = `You are helping me turn a raw product idea into a structured product spec.
226
-
227
- My raw idea: [describe your idea in 2-5 sentences — audience, problem, what you imagine building]
228
-
229
- I'm building a ${productType.label.toLowerCase()} called "${projectNameRaw}".
230
-
231
- I want you to fill out the following template completely. Do not skip
232
- sections. If you don't have enough information for a section, ask me a
233
- specific clarifying question instead of writing a generic placeholder.
234
-
235
- Push back on weak answers — if my problem statement is vague ("things are
236
- hard"), ask me to quantify it. If my target audience is "everyone," force me
237
- to pick a primary segment.
238
-
239
- Here is the template to fill:
240
-
241
- ${rawProjectMd}
242
-
243
- Output the completed template in the same markdown format, ready to save
244
- back into docs/PROJECT.md.`;
245
-
246
- fs.writeFileSync(path.join(docsDir, "FIRST_PROMPT.txt"), prompt);
247
-
248
- const toolNote = aiTool.note;
249
- const nextSteps = `# Next Steps for ${projectNameRaw}
250
-
251
- You're building: **${productType.label}**
252
- Your AI tool: **${aiTool.key}**
253
-
254
- ## 1. Run the app shell (optional, do this anytime)
255
-
256
- \`\`\`
257
- cd ${projectSlug}
258
- npm install
259
- npm run dev
260
- \`\`\`
261
-
262
- Then open http://localhost:3000 — you'll see the sale page, member area, and
263
- backoffice already wired up with placeholder/mock data.
264
-
265
- ## 2. Fill in your product spec (do this first, before changing code)
266
-
267
- Open \`docs/PROJECT.md\`. It's pre-filled with your project name and product
268
- type. Fill in sections 1-2 (Vision, Problem Statement) yourself, by hand —
269
- this is the thinking only you can do.
270
-
271
- ## 3. Let AI fill in the rest
272
-
273
- ${toolNote}
274
-
275
- The exact prompt to paste is saved in \`docs/FIRST_PROMPT.txt\` — open it,
276
- fill in the [raw idea] bracket, and paste the whole thing into ${aiTool.key}.
277
-
278
- ## 4. Keep going
446
+ // Tech-stack reference agent reads this when making stack decisions.
447
+ // (Design system is NOT bundled as a static file the /build command
448
+ // invokes the ui-ux-pro-max skill to generate one specific to this project.)
449
+ const techStackSrc = path.join(TEMPLATES_DIR, "docs", "tech-stack");
450
+ if (fs.existsSync(techStackSrc)) {
451
+ copyRecursiveExcluding(techStackSrc, path.join(docsDir, "tech-stack"), new Set());
452
+ }
279
453
 
280
- Once \`docs/PROJECT.md\` is fully filled (no more [brackets]):
281
- - Move to \`docs/HUMAN_FLOW.md\` (Stage 2 in the prompt chain)
282
- - Reference \`docs/${productType.file}\` for feature ideas specific to a ${productType.label.toLowerCase()}
283
- - The full prompt chain (Stage 3-6: UX -> Tech -> Build Plan -> Code) is in
284
- \`docs/PROMPTS.md\` — already copied into this project
454
+ // ── 8. npm install ─────────────────────────────────────────────────────
455
+ console.log("\nInstalling packages (this takes ~30 seconds)...");
456
+ const install = spawnSync("npm", ["install"], {
457
+ cwd: outDir,
458
+ stdio: "inherit",
459
+ shell: true,
460
+ });
461
+ if (install.status !== 0) {
462
+ console.log(`\n npm install failed. Run it manually:\n cd ${projectSlug} && npm install`);
463
+ }
285
464
 
286
- ## 5. Coding agents are already configured
465
+ // ── 9. Done ────────────────────────────────────────────────────────────
466
+ console.log(`
467
+ Done! Your project is at: ./${projectSlug}/
287
468
 
288
- This folder includes AGENTS.md / CLAUDE.md / .cursorrules / .windsurfrules.
289
- If you open this folder in Cursor, Windsurf, or Claude Code, those tools
290
- will automatically enforce filling Structure and Human Flow before
291
- generating feature code — you don't need to do anything extra.
469
+ docs/PROJECT.md product spec (pre-filled)
470
+ docs/HUMAN_FLOW.md — UX flow (pre-filled)
471
+ docs/tech-stack/STACK_DECISION_MATRIX.md — stack choices reference
292
472
 
293
- If you use Claude Code specifically, there's also a \`.claude/skills/ship-method/SKILL.md\`
294
- — Claude can invoke it directly as a skill (not just a passive rule file)
295
- whenever you ask it to build a feature or review whether something is
296
- ready to ship.
297
- `;
473
+ ── Open in your AI coding tool and type /build ─────────────────
298
474
 
299
- fs.writeFileSync(path.join(outDir, "NEXT_STEPS.md"), nextSteps);
475
+ Claude Code → claude ./${projectSlug}
476
+ Cursor → cursor ./${projectSlug}
477
+ Windsurf → windsurf ./${projectSlug}
300
478
 
301
- console.log("\nDone! Your project is ready at:");
302
- console.log(` ./${projectSlug}/`);
303
- console.log("\nOpen this file for what to do next:");
304
- console.log(` ${projectSlug}/NEXT_STEPS.md`);
305
- console.log("\nOr just run:");
306
- console.log(` cat "${projectSlug}/NEXT_STEPS.md"`);
479
+ Then type: /build
307
480
 
308
- rl.close();
481
+ The agent will read your docs, create the build spec, pick a theme,
482
+ and start coding the MVP — no copy-paste, no extra setup.
483
+ `);
309
484
  }
310
485
 
311
486
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ship-create",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "Scaffold a new project the SHIP Method way — Structure, Human Flow, Instruction, Publish. No git clone, no API key, just one command.",
5
5
  "type": "module",
6
6
  "license": "MIT",