@girardmedia/bootspring 2.5.1 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -3378,7 +3378,7 @@ var init_release = __esm({
3378
3378
  "../../packages/shared/src/release.ts"() {
3379
3379
  "use strict";
3380
3380
  init_cjs_shims();
3381
- BOOTSPRING_VERSION = "2.5.0";
3381
+ BOOTSPRING_VERSION = "2.5.3";
3382
3382
  BOOTSPRING_PACKAGE_NAME = "@girardmedia/bootspring";
3383
3383
  }
3384
3384
  });
@@ -5195,8 +5195,12 @@ var init_setup_commands = __esm({
5195
5195
  var tier_enforcement_exports = {};
5196
5196
  __export(tier_enforcement_exports, {
5197
5197
  AGENT_TIERS: () => AGENT_TIERS,
5198
+ CUSTOM_PROMPTS_TIERS: () => CUSTOM_PROMPTS_TIERS,
5198
5199
  DEFAULT_LIMITS: () => DEFAULT_LIMITS,
5200
+ DUAL_LLM_TIERS: () => DUAL_LLM_TIERS,
5199
5201
  FEATURE_GATES: () => FEATURE_GATES,
5202
+ FREE_AGENTS: () => FREE_AGENTS,
5203
+ GENERATION_LIMITS: () => GENERATION_LIMITS,
5200
5204
  PREMIUM_SKILL_CATEGORIES: () => PREMIUM_SKILL_CATEGORIES,
5201
5205
  PREMIUM_SKILL_PATTERNS: () => PREMIUM_SKILL_PATTERNS,
5202
5206
  PRESEED_PAID_COMMANDS: () => PRESEED_PAID_COMMANDS,
@@ -5204,6 +5208,9 @@ __export(tier_enforcement_exports, {
5204
5208
  TIER_HIERARCHY: () => TIER_HIERARCHY,
5205
5209
  cacheEntitlements: () => cacheEntitlements,
5206
5210
  checkAgentAccess: () => checkAgentAccess,
5211
+ checkCustomPromptsAccess: () => checkCustomPromptsAccess,
5212
+ checkDualLlmAccess: () => checkDualLlmAccess,
5213
+ checkGenerationAccess: () => checkGenerationAccess,
5207
5214
  checkLimit: () => checkLimit,
5208
5215
  checkPreseedAccess: () => checkPreseedAccess,
5209
5216
  checkSeedAccess: () => checkSeedAccess,
@@ -5323,8 +5330,14 @@ function meetsTierRequirement(requiredTier, userTier = null) {
5323
5330
  return getTierLevel(user) >= getTierLevel(requiredTier);
5324
5331
  }
5325
5332
  function checkAgentAccess(agentId) {
5326
- const requiredTier = AGENT_TIERS[agentId];
5327
5333
  const userTier = getTier2();
5334
+ if (getTierLevel(userTier) === 0) {
5335
+ if (!FREE_AGENTS.has(agentId)) {
5336
+ return { allowed: false, requiredTier: "pro", userTier };
5337
+ }
5338
+ return { allowed: true, userTier };
5339
+ }
5340
+ const requiredTier = AGENT_TIERS[agentId];
5328
5341
  if (!requiredTier) {
5329
5342
  return { allowed: true, userTier };
5330
5343
  }
@@ -5595,7 +5608,18 @@ function requireSeedAccess(command) {
5595
5608
  throw error50;
5596
5609
  }
5597
5610
  }
5598
- var fs8, os5, path8, BOOTSPRING_DIR2, ENTITLEMENTS_CACHE_FILE, CACHE_TTL_MS, TIER_HIERARCHY, DEFAULT_LIMITS, FEATURE_GATES, PRESEED_PAID_COMMANDS, SEED_PAID_COMMANDS, AGENT_TIERS, PREMIUM_SKILL_CATEGORIES, PREMIUM_SKILL_PATTERNS, FREE_SKILL_OVERRIDES, UPGRADE_URL, FEATURE_COPY;
5611
+ function checkGenerationAccess() {
5612
+ const tier = getTier2();
5613
+ const limit = GENERATION_LIMITS[tier] ?? 0;
5614
+ return { allowed: limit > 0, limit, tier };
5615
+ }
5616
+ function checkCustomPromptsAccess() {
5617
+ return CUSTOM_PROMPTS_TIERS.has(getTier2());
5618
+ }
5619
+ function checkDualLlmAccess() {
5620
+ return DUAL_LLM_TIERS.has(getTier2());
5621
+ }
5622
+ var fs8, os5, path8, BOOTSPRING_DIR2, ENTITLEMENTS_CACHE_FILE, CACHE_TTL_MS, TIER_HIERARCHY, DEFAULT_LIMITS, FEATURE_GATES, PRESEED_PAID_COMMANDS, SEED_PAID_COMMANDS, AGENT_TIERS, FREE_AGENTS, PREMIUM_SKILL_CATEGORIES, PREMIUM_SKILL_PATTERNS, GENERATION_LIMITS, CUSTOM_PROMPTS_TIERS, DUAL_LLM_TIERS, FREE_SKILL_OVERRIDES, UPGRADE_URL, FEATURE_COPY;
5599
5623
  var init_tier_enforcement = __esm({
5600
5624
  "../../packages/core/src/tier-enforcement.ts"() {
5601
5625
  "use strict";
@@ -5617,11 +5641,12 @@ var init_tier_enforcement = __esm({
5617
5641
  custom: 3
5618
5642
  };
5619
5643
  DEFAULT_LIMITS = {
5620
- free: { projects: 1, apiCallsPerMonth: 500, devices: 1, teamSeats: 1, storage: "100MB" },
5621
- founder: { projects: 5, apiCallsPerMonth: 1e4, devices: 3, teamSeats: 1, storage: "5GB" },
5622
- pro: { projects: 5, apiCallsPerMonth: 1e4, devices: 3, teamSeats: 1, storage: "5GB" },
5623
- team: { projects: 20, apiCallsPerMonth: 5e4, devices: 10, teamSeats: 5, storage: "50GB" },
5624
- enterprise: { projects: 100, apiCallsPerMonth: 5e5, devices: 50, teamSeats: 20, storage: "500GB" },
5644
+ free: { projects: 1, apiCallsPerMonth: 100, devices: 1, teamSeats: 1, storage: "50MB" },
5645
+ // one-time trial credits, not recurring
5646
+ founder: { projects: 5, apiCallsPerMonth: 5e3, devices: 1, teamSeats: 1, storage: "2GB" },
5647
+ pro: { projects: 5, apiCallsPerMonth: 5e3, devices: 1, teamSeats: 1, storage: "2GB" },
5648
+ team: { projects: 15, apiCallsPerMonth: 25e3, devices: 2, teamSeats: 3, storage: "25GB" },
5649
+ enterprise: { projects: 50, apiCallsPerMonth: 1e5, devices: 5, teamSeats: 10, storage: "250GB" },
5625
5650
  custom: { projects: 999, apiCallsPerMonth: 999999, devices: 999, teamSeats: 999, storage: "1TB" }
5626
5651
  };
5627
5652
  FEATURE_GATES = {
@@ -5680,6 +5705,7 @@ var init_tier_enforcement = __esm({
5680
5705
  "priority_support",
5681
5706
  "team_features",
5682
5707
  "presence",
5708
+ "custom_policies",
5683
5709
  "preseed.*",
5684
5710
  "seed.*"
5685
5711
  ],
@@ -5715,18 +5741,28 @@ var init_tier_enforcement = __esm({
5715
5741
  PRESEED_PAID_COMMANDS = ["pull", "push", "workflow", "merge", "start"];
5716
5742
  SEED_PAID_COMMANDS = ["scaffold", "synthesize", "generate"];
5717
5743
  AGENT_TIERS = {
5744
+ // Business agents — Pro tier
5718
5745
  "business-strategy-expert": "pro",
5719
5746
  "competitive-analysis-expert": "pro",
5720
5747
  "financial-expert": "pro",
5748
+ "fundraising-expert": "pro",
5721
5749
  "growth-expert": "pro",
5750
+ "investor-relations-expert": "pro",
5722
5751
  "legal-expert": "pro",
5723
5752
  "operations-expert": "pro",
5753
+ "partnerships-expert": "pro",
5754
+ "private-equity-expert": "pro",
5724
5755
  "sales-expert": "pro",
5725
- "fundraising-expert": "team",
5726
- "investor-relations-expert": "team",
5727
- "partnerships-expert": "team",
5728
- "private-equity-expert": "team"
5729
- };
5756
+ // Design agent — Pro tier
5757
+ "ui-ux-expert": "pro",
5758
+ "content-expert": "pro",
5759
+ "marketing-expert": "pro",
5760
+ "product-expert": "pro"
5761
+ };
5762
+ FREE_AGENTS = /* @__PURE__ */ new Set([
5763
+ "database-expert",
5764
+ "frontend-expert"
5765
+ ]);
5730
5766
  PREMIUM_SKILL_CATEGORIES = [
5731
5767
  "ai",
5732
5768
  "payments",
@@ -5752,6 +5788,16 @@ var init_tier_enforcement = __esm({
5752
5788
  "ui/command-palette",
5753
5789
  "ui/data-tables"
5754
5790
  ];
5791
+ GENERATION_LIMITS = {
5792
+ free: 0,
5793
+ founder: 25,
5794
+ pro: 25,
5795
+ team: 100,
5796
+ enterprise: 500,
5797
+ custom: 999999
5798
+ };
5799
+ CUSTOM_PROMPTS_TIERS = /* @__PURE__ */ new Set(["enterprise", "custom"]);
5800
+ DUAL_LLM_TIERS = /* @__PURE__ */ new Set(["enterprise", "custom"]);
5755
5801
  FREE_SKILL_OVERRIDES = ["security/validation", "deployment/docker"];
5756
5802
  UPGRADE_URL = "https://bootspring.com/pricing";
5757
5803
  FEATURE_COPY = {
@@ -48405,22 +48451,97 @@ init_cjs_shims();
48405
48451
  var fs25 = __toESM(require("fs"));
48406
48452
  var path27 = __toESM(require("path"));
48407
48453
  init_src();
48454
+ var DOCUMENT_TYPES = {
48455
+ vision: {
48456
+ name: "VISION.md",
48457
+ title: "Vision Document",
48458
+ description: "Problem statement, solution overview, and core values",
48459
+ priority: 1,
48460
+ required: true
48461
+ },
48462
+ audience: {
48463
+ name: "AUDIENCE.md",
48464
+ title: "Target Audience",
48465
+ description: "Target audience, personas, and ideal customer profile",
48466
+ priority: 2,
48467
+ required: true
48468
+ },
48469
+ market: {
48470
+ name: "MARKET.md",
48471
+ title: "Market Analysis",
48472
+ description: "TAM/SAM/SOM analysis and market opportunity",
48473
+ priority: 3,
48474
+ required: false
48475
+ },
48476
+ competitors: {
48477
+ name: "COMPETITORS.md",
48478
+ title: "Competitive Analysis",
48479
+ description: "Competitive landscape, positioning, and differentiation",
48480
+ priority: 4,
48481
+ required: false
48482
+ },
48483
+ "business-model": {
48484
+ name: "BUSINESS_MODEL.md",
48485
+ title: "Business Model",
48486
+ description: "Value proposition, revenue model, and pricing strategy",
48487
+ priority: 5,
48488
+ required: true
48489
+ },
48490
+ prd: {
48491
+ name: "PRD.md",
48492
+ title: "Product Requirements",
48493
+ description: "Product vision, user stories, and MVP scope",
48494
+ priority: 6,
48495
+ required: true
48496
+ },
48497
+ "technical-spec": {
48498
+ name: "TECHNICAL_SPEC.md",
48499
+ title: "Technical Specification",
48500
+ description: "Architecture, tech stack, and data model",
48501
+ priority: 7,
48502
+ required: false
48503
+ },
48504
+ roadmap: {
48505
+ name: "ROADMAP.md",
48506
+ title: "Product Roadmap",
48507
+ description: "Phased development plan and milestones",
48508
+ priority: 8,
48509
+ required: false
48510
+ }
48511
+ };
48408
48512
  var PRESETS = {
48409
- startup: ["vision", "market", "competitors", "personas", "roadmap"],
48410
- enterprise: ["vision", "market", "competitors", "personas", "roadmap", "compliance", "security"],
48411
- minimal: ["vision", "roadmap"],
48412
- full: ["vision", "market", "competitors", "personas", "roadmap", "compliance", "security", "architecture"]
48513
+ essential: ["vision", "audience", "business-model", "prd"],
48514
+ startup: ["vision", "audience", "market", "competitors", "business-model", "prd", "roadmap"],
48515
+ full: Object.keys(DOCUMENT_TYPES),
48516
+ technical: ["vision", "prd", "technical-spec", "roadmap"],
48517
+ investor: ["vision", "audience", "market", "competitors", "business-model", "roadmap"]
48413
48518
  };
48519
+ var CONTEXT_FOLDERS = {
48520
+ drop: { name: "drop", description: "Drop anything here - AI will sort it out", isUniversal: true },
48521
+ ideas: { name: "ideas", description: "Rough ideas, brainstorms, notes" },
48522
+ research: { name: "research", description: "Market research, industry reports" },
48523
+ vision: { name: "vision", description: "Vision statements, problem/solution notes", mapsTo: "vision" },
48524
+ audience: { name: "audience", description: "User interviews, surveys, personas", mapsTo: "audience" },
48525
+ market: { name: "market", description: "Market size, TAM/SAM/SOM analysis, trends", mapsTo: "market" },
48526
+ competitors: { name: "competitors", description: "Competitor analysis, screenshots, comparisons", mapsTo: "competitors" },
48527
+ business: { name: "business", description: "Business model ideas, pricing notes, revenue", mapsTo: "business-model" },
48528
+ prd: { name: "prd", description: "Product requirements, user stories, features", mapsTo: "prd" },
48529
+ technical: { name: "technical", description: "Technical requirements, architecture notes", mapsTo: "technical-spec" },
48530
+ roadmap: { name: "roadmap", description: "Timeline notes, milestones, phasing plans", mapsTo: "roadmap" }
48531
+ };
48532
+ var DEFAULT_OUTPUT_DIR = ".bootspring/preseed";
48533
+ var CONTEXT_INPUT_DIR = ".bootspring/preseed/context";
48534
+ var CONFIG_FILE2 = "PRESEED_CONFIG.json";
48414
48535
  function ensurePreseedDir() {
48415
- const dir = path27.join(process.cwd(), ".bootspring", "preseed");
48536
+ const dir = path27.join(process.cwd(), DEFAULT_OUTPUT_DIR);
48416
48537
  if (!fs25.existsSync(dir)) {
48417
48538
  fs25.mkdirSync(dir, { recursive: true });
48418
48539
  }
48419
48540
  return dir;
48420
48541
  }
48421
48542
  function getPreseedStatus() {
48422
- const dir = path27.join(process.cwd(), ".bootspring", "preseed");
48423
- const configFile = path27.join(process.cwd(), ".bootspring", "preseed-config.json");
48543
+ const dir = path27.join(process.cwd(), DEFAULT_OUTPUT_DIR);
48544
+ const configFile = path27.join(dir, CONFIG_FILE2);
48424
48545
  const hasConfig = fs25.existsSync(configFile);
48425
48546
  if (!fs25.existsSync(dir)) {
48426
48547
  return { generated: [], total: 0, hasConfig };
@@ -48428,130 +48549,832 @@ function getPreseedStatus() {
48428
48549
  const files = fs25.readdirSync(dir).filter((f) => f.endsWith(".md"));
48429
48550
  return { generated: files, total: files.length, hasConfig };
48430
48551
  }
48552
+ function generateContextReadme() {
48553
+ return `# Preseed Context Documents
48554
+
48555
+ ## Complete Workflow (10 Steps)
48556
+
48557
+ ### Quick Start (one command does it all)
48558
+ \`\`\`bash
48559
+ bootspring preseed go
48560
+ \`\`\`
48561
+ This runs the full workflow automatically: setup \u2192 detect codebase \u2192 generate docs \u2192 show status.
48562
+
48563
+ ### Step-by-Step (advanced / granular control)
48564
+
48565
+ | Step | Command | What It Does |
48566
+ |------|---------|--------------|
48567
+ | 1 | \`bootspring preseed start\` | Detect your environment and see recommended next steps |
48568
+ | 2 | \`bootspring preseed init\` | Create folder structure + empty PRESEED_CONFIG.json |
48569
+ | 3 | *(optional)* Drop files in \`context/\` subfolders | Add pitch decks, notes, research \u2014 AI uses them to enrich docs |
48570
+ | 4 | \`bootspring preseed from-codebase\` | Auto-detect tech stack from package.json and generate config |
48571
+ | 5 | \`bootspring preseed generate\` | Generate all preseed markdown documents from config |
48572
+ | 6 | Edit the generated \`.md\` files in \`.bootspring/preseed/\` | Fill in your vision, audience, market, etc. |
48573
+ | 7 | \`bootspring preseed status\` | Check which documents exist and their completeness |
48574
+ | 8 | \`bootspring preseed merge\` | Combine all docs into a single SEED.md |
48575
+ | 9 | \`bootspring preseed workflow start\` | Begin document review/approval workflow |
48576
+ | 10 | \`bootspring build start\` | Transition from preseed into the build phase |
48577
+
48578
+ ### For New Projects (no existing code)
48579
+ \`\`\`bash
48580
+ bootspring preseed init # Step 2: Create folder structure
48581
+ # Drop any notes/research into .bootspring/preseed/context/drop/
48582
+ bootspring preseed generate # Step 5: Generate document templates
48583
+ # Edit the generated .md files with your project details
48584
+ bootspring preseed merge # Step 8: Create unified SEED.md
48585
+ bootspring build start # Step 10: Begin building
48586
+ \`\`\`
48587
+
48588
+ ### For Existing Codebases
48589
+ \`\`\`bash
48590
+ bootspring preseed go # Does steps 2-5 automatically
48591
+ # Edit the generated .md files to refine
48592
+ bootspring preseed merge # Step 8: Create unified SEED.md
48593
+ bootspring build start # Step 10: Begin building
48594
+ \`\`\`
48595
+
48596
+ ---
48597
+
48598
+ ## Context Folder Reference
48599
+
48600
+ **Don't know where to put something?** Just drop it in the \`drop/\` folder.
48601
+ AI will analyze your files and extract relevant information for each preseed document.
48602
+
48603
+ ### Universal
48604
+ | Folder | What to put here |
48605
+ |--------|------------------|
48606
+ | \`drop/\` | **Anything!** Pitch decks, notes, docs \u2014 AI sorts it out |
48607
+
48608
+ ### General
48609
+ | Folder | What to put here |
48610
+ |--------|------------------|
48611
+ | \`ideas/\` | Rough ideas, brainstorms, notes |
48612
+ | \`research/\` | Market research, industry reports |
48613
+
48614
+ ### Document-specific (maps 1:1 to output)
48615
+ | Folder | Output Document |
48616
+ |--------|-----------------|
48617
+ | \`vision/\` | \u2192 VISION.md |
48618
+ | \`audience/\` | \u2192 AUDIENCE.md |
48619
+ | \`market/\` | \u2192 MARKET.md |
48620
+ | \`competitors/\` | \u2192 COMPETITORS.md |
48621
+ | \`business/\` | \u2192 BUSINESS_MODEL.md |
48622
+ | \`prd/\` | \u2192 PRD.md |
48623
+ | \`technical/\` | \u2192 TECHNICAL_SPEC.md |
48624
+ | \`roadmap/\` | \u2192 ROADMAP.md |
48625
+
48626
+ ### Supported Formats
48627
+ Markdown (.md), Text (.txt), PDF (.pdf), Word (.docx), CSV (.csv), Images (.png, .jpg)
48628
+
48629
+ ## Tips
48630
+
48631
+ - More context = better generated documents
48632
+ - Each folder maps 1:1 to an output document for easy organization
48633
+ - Even rough notes are valuable \u2014 **not sure where something goes? Use \`drop/\`!**
48634
+ - Include any competitor URLs or screenshots
48635
+ - Add user interview transcripts if available
48636
+ `;
48637
+ }
48638
+ function generateDocumentContent(docType, projectName, preset) {
48639
+ const date7 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
48640
+ const meta3 = DOCUMENT_TYPES[docType];
48641
+ const title = meta3?.title ?? docType.charAt(0).toUpperCase() + docType.slice(1);
48642
+ const fileName = meta3?.name ?? `${docType.toUpperCase()}.md`;
48643
+ const templates = {
48644
+ vision: `# ${projectName}
48645
+
48646
+ > *Your tagline here*
48647
+
48648
+ **Category:** SaaS
48649
+ **Generated:** ${date7}
48650
+ **Status:** Draft
48651
+
48652
+ ## The Problem
48653
+
48654
+ *Describe the core problem your product solves. What pain points do users experience today?*
48655
+
48656
+ ### Key Challenges
48657
+
48658
+ - *Challenge 1: Describe a specific pain point*
48659
+ - *Challenge 2: Describe another pain point*
48660
+ - *Challenge 3: Describe another pain point*
48661
+
48662
+ ### Current Solutions (and their limitations)
48663
+
48664
+ - **Existing Solution A**: *What limitation does it have?*
48665
+ - **Existing Solution B**: *What limitation does it have?*
48666
+
48667
+ ### Why Now?
48668
+
48669
+ *What has changed in the market, technology, or user behavior that makes this the right time?*
48670
+
48671
+ ## Our Solution
48672
+
48673
+ *Describe your solution at a high level. What does it do and why is it better?*
48674
+
48675
+ ### Key Capabilities
48676
+
48677
+ - **Feature 1**: *Brief description*
48678
+ - **Feature 2**: *Brief description*
48679
+ - **Feature 3**: *Brief description*
48680
+
48681
+ ### Unique Value Proposition
48682
+
48683
+ *What makes your product uniquely better? Why would someone switch from their current solution?*
48684
+
48685
+ ---
48686
+
48687
+ *This is a living document generated by Bootspring. Run \`bootspring preseed sync\` to update.*
48688
+ `,
48689
+ audience: `# ${projectName} - Target Audience
48690
+
48691
+ **Generated:** ${date7}
48692
+ **Status:** Draft
48693
+
48694
+ ## Primary Audience
48695
+
48696
+ *Who is the main user of your product? Be specific about role, industry, and company size.*
48697
+
48698
+ ## Market Segments
48699
+
48700
+ ### Segment 1
48701
+ - **Description**: *Who are they?*
48702
+ - **Size**: *How many potential users?*
48703
+ - **Characteristics**: *What defines this segment?*
48704
+
48705
+ ### Segment 2
48706
+ - **Description**: *Who are they?*
48707
+ - **Size**: *How many potential users?*
48708
+ - **Characteristics**: *What defines this segment?*
48709
+
48710
+ ## User Personas
48711
+
48712
+ ### Persona 1
48713
+ - **Role**: *Job title / role*
48714
+ - **Demographics**: *Age, experience level, tech savviness*
48715
+ - **Goals**: *What are they trying to achieve?*
48716
+ - **Pain Points**: *What frustrates them about current solutions?*
48717
+ - **Quote**: *"A representative quote from this persona"*
48718
+
48719
+ ### Persona 2
48720
+ - **Role**: *Job title / role*
48721
+ - **Demographics**: *Age, experience level, tech savviness*
48722
+ - **Goals**: *What are they trying to achieve?*
48723
+ - **Pain Points**: *What frustrates them?*
48724
+ - **Quote**: *"A representative quote"*
48725
+
48726
+ ## Ideal Customer Profile (ICP)
48727
+
48728
+ | Attribute | Value |
48729
+ |-----------|-------|
48730
+ | Company Size | *e.g., 10-500 employees* |
48731
+ | Industry | *e.g., Technology, SaaS* |
48732
+ | Budget | *e.g., $50-500/mo* |
48733
+ | Decision Maker | *e.g., Engineering Manager* |
48734
+ | Buying Process | *e.g., Self-serve, sales-assisted* |
48735
+
48736
+ ---
48737
+
48738
+ *Generated by Bootspring Preseed*
48739
+ `,
48740
+ market: `# ${projectName} - Market Analysis
48741
+
48742
+ **Generated:** ${date7}
48743
+ **Status:** Draft
48744
+
48745
+ ## Market Size
48746
+
48747
+ | Metric | Value | Rationale |
48748
+ |--------|-------|-----------|
48749
+ | **TAM** (Total Addressable Market) | *$X billion* | *How did you calculate this?* |
48750
+ | **SAM** (Serviceable Addressable Market) | *$X million* | *Your accessible subset* |
48751
+ | **SOM** (Serviceable Obtainable Market) | *$X million* | *Realistic 3-year target* |
48752
+
48753
+ ## Market Trends
48754
+
48755
+ - **Trend 1**: *Description and impact on your product*
48756
+ - **Trend 2**: *Description and impact on your product*
48757
+ - **Trend 3**: *Description and impact on your product*
48758
+
48759
+ ## Growth Drivers
48760
+
48761
+ *What factors are driving market growth? Why is demand increasing?*
48762
+
48763
+ ## Market Challenges
48764
+
48765
+ *What headwinds exist? Regulatory, economic, or competitive pressures?*
48766
+
48767
+ ---
48768
+
48769
+ *Generated by Bootspring Preseed*
48770
+ `,
48771
+ competitors: `# ${projectName} - Competitive Analysis
48772
+
48773
+ **Generated:** ${date7}
48774
+ **Status:** Draft
48775
+
48776
+ ## Direct Competitors
48777
+
48778
+ ### Competitor 1
48779
+ - **Strengths**: *What they do well*
48780
+ - **Weaknesses**: *Where they fall short*
48781
+ - **Pricing**: *Their pricing model*
48782
+ - **Why users choose them**: *Key value proposition*
48783
+ - **Limitations**: *Key limitations*
48784
+
48785
+ ### Competitor 2
48786
+ - **Strengths**: *What they do well*
48787
+ - **Weaknesses**: *Where they fall short*
48788
+ - **Pricing**: *Their pricing model*
48789
+ - **Why users choose them**: *Key value proposition*
48790
+ - **Limitations**: *Key limitations*
48791
+
48792
+ ## Indirect Competitors / Alternatives
48793
+
48794
+ - **Alternative 1**: *How users currently solve this problem without a dedicated tool*
48795
+ - **Alternative 2**: *Another workaround users employ*
48796
+
48797
+ ## Competitive Positioning
48798
+
48799
+ *Where does your product sit relative to competitors? What axis do you win on?*
48800
+
48801
+ ## Key Differentiators
48802
+
48803
+ - *Differentiator 1*
48804
+ - *Differentiator 2*
48805
+ - *Differentiator 3*
48806
+
48807
+ ---
48808
+
48809
+ *Generated by Bootspring Preseed*
48810
+ `,
48811
+ "business-model": `# ${projectName} - Business Model
48812
+
48813
+ **Generated:** ${date7}
48814
+ **Status:** Draft
48815
+
48816
+ ## Business Model
48817
+
48818
+ *Describe your primary business model (subscription, freemium, usage-based, marketplace, etc.)*
48819
+
48820
+ ## Revenue Streams
48821
+
48822
+ | Stream | Description | % of Revenue |
48823
+ |--------|-------------|-------------|
48824
+ | *Primary* | *e.g., Monthly subscription* | *80%* |
48825
+ | *Secondary* | *e.g., Professional services* | *20%* |
48826
+
48827
+ ## Pricing Strategy
48828
+
48829
+ ### Tier 1: Free
48830
+ - *Feature 1*
48831
+ - *Feature 2*
48832
+
48833
+ ### Tier 2: Pro ($X/mo)
48834
+ - *Everything in Free*
48835
+ - *Feature 3*
48836
+ - *Feature 4*
48837
+
48838
+ ### Tier 3: Enterprise (Custom)
48839
+ - *Everything in Pro*
48840
+ - *Feature 5*
48841
+ - *Feature 6*
48842
+
48843
+ ## Unit Economics
48844
+
48845
+ | Metric | Value |
48846
+ |--------|-------|
48847
+ | **CAC** (Customer Acquisition Cost) | *$X* |
48848
+ | **LTV** (Lifetime Value) | *$X* |
48849
+ | **LTV:CAC Ratio** | *X:1* |
48850
+ | **Payback Period** | *X months* |
48851
+ | **Gross Margin** | *X%* |
48852
+
48853
+ ---
48854
+
48855
+ *Generated by Bootspring Preseed*
48856
+ `,
48857
+ prd: `# ${projectName} - Product Requirements Document
48858
+
48859
+ **Generated:** ${date7}
48860
+ **Status:** Draft
48861
+
48862
+ ## Product Vision
48863
+
48864
+ *One paragraph describing what the product will become and the impact it will have.*
48865
+
48866
+ ## MVP Features
48867
+
48868
+ | Feature | Description | Priority |
48869
+ |---------|-------------|----------|
48870
+ | *Feature 1* | *What it does* | Must-have |
48871
+ | *Feature 2* | *What it does* | Must-have |
48872
+ | *Feature 3* | *What it does* | Should-have |
48873
+ | *Feature 4* | *What it does* | Nice-to-have |
48874
+
48875
+ ## User Stories
48876
+
48877
+ ### Core Workflows
48878
+
48879
+ - **As a** *[user type]*, **I want to** *[action]*, **so that** *[benefit]*
48880
+ - **As a** *[user type]*, **I want to** *[action]*, **so that** *[benefit]*
48881
+ - **As a** *[user type]*, **I want to** *[action]*, **so that** *[benefit]*
48882
+
48883
+ ## Future Features (Post-MVP)
48884
+
48885
+ - *Feature 5*
48886
+ - *Feature 6*
48887
+ - *Feature 7*
48888
+
48889
+ ## Success Metrics
48890
+
48891
+ | Metric | Target | Timeframe |
48892
+ |--------|--------|-----------|
48893
+ | *Active Users* | *X* | *3 months* |
48894
+ | *Retention Rate* | *X%* | *Monthly* |
48895
+ | *NPS Score* | *X* | *Quarterly* |
48896
+
48897
+ ---
48898
+
48899
+ *Generated by Bootspring Preseed*
48900
+ `,
48901
+ "technical-spec": `# ${projectName} - Technical Specification
48902
+
48903
+ **Generated:** ${date7}
48904
+ **Status:** Draft
48905
+
48906
+ ## Tech Stack
48907
+
48908
+ | Component | Technology | Rationale |
48909
+ |-----------|------------|-----------|
48910
+ | Frontend | *e.g., Next.js / React* | *Why this choice?* |
48911
+ | Backend | *e.g., Node.js / Express* | *Why this choice?* |
48912
+ | Database | *e.g., PostgreSQL* | *Why this choice?* |
48913
+ | Auth | *e.g., NextAuth / Clerk* | *Why this choice?* |
48914
+ | Hosting | *e.g., Vercel / AWS* | *Why this choice?* |
48915
+
48916
+ ## Architecture
48917
+
48918
+ *Describe the high-level architecture: monolith vs microservices, API design, data flow.*
48919
+
48920
+ ## Data Model
48921
+
48922
+ *List the core entities and their relationships.*
48923
+
48924
+ ## Integrations
48925
+
48926
+ | Integration | Purpose |
48927
+ |-------------|---------|
48928
+ | *e.g., Stripe* | *Payment processing* |
48929
+ | *e.g., SendGrid* | *Transactional email* |
48930
+
48931
+ ## Technical Constraints
48932
+
48933
+ - *Constraint 1*
48934
+ - *Constraint 2*
48935
+
48936
+ ---
48937
+
48938
+ *Generated by Bootspring Preseed*
48939
+ `,
48940
+ roadmap: `# ${projectName} - Product Roadmap
48941
+
48942
+ **Generated:** ${date7}
48943
+ **Status:** Draft
48944
+
48945
+ ## Timeline Overview
48946
+
48947
+ *High-level timeline from MVP to mature product.*
48948
+
48949
+ ## Phase 1: Foundation (Weeks 1-4)
48950
+ - **Goal**: *MVP with core functionality*
48951
+ - **Deliverables**:
48952
+ - *Deliverable 1*
48953
+ - *Deliverable 2*
48954
+ - *Deliverable 3*
48955
+
48956
+ ## Phase 2: Growth (Months 2-3)
48957
+ - **Goal**: *Scale user base, add key features*
48958
+ - **Deliverables**:
48959
+ - *Deliverable 1*
48960
+ - *Deliverable 2*
48961
+
48962
+ ## Phase 3: Scale (Months 3-6)
48963
+ - **Goal**: *Enterprise features, market expansion*
48964
+ - **Deliverables**:
48965
+ - *Deliverable 1*
48966
+ - *Deliverable 2*
48967
+
48968
+ ## Key Milestones
48969
+
48970
+ | Milestone | Target Date | Status |
48971
+ |-----------|------------|--------|
48972
+ | *MVP Launch* | *TBD* | Planned |
48973
+ | *First 100 Users* | *TBD* | Planned |
48974
+ | *Revenue Target* | *TBD* | Planned |
48975
+
48976
+ ---
48977
+
48978
+ *Generated by Bootspring Preseed*
48979
+ `
48980
+ };
48981
+ return templates[docType] ?? `# ${projectName} - ${title}
48982
+
48983
+ **Generated:** ${date7}
48984
+ **Status:** Draft
48985
+ **Source:** Preseed (${preset})
48986
+
48987
+ ## Overview
48988
+
48989
+ *Add ${title.toLowerCase()} details for ${projectName}.*
48990
+
48991
+ ---
48992
+
48993
+ *Generated by Bootspring Preseed*
48994
+ `;
48995
+ }
48431
48996
  function registerPreseedCommand(program3) {
48432
48997
  const preseed = program3.command("preseed").description("Generate foundational documents from minimal input");
48433
48998
  preseed.command("start").description("Smart entry point - detects context and guides you").option("--preset <preset>", "Preset to use (startup, enterprise, minimal, full)", "startup").action(async (opts) => {
48434
48999
  print.header("Preseed Start");
48435
49000
  const cwd = process.cwd();
48436
49001
  const status = getPreseedStatus();
49002
+ const hasPkg = fs25.existsSync(path27.join(cwd, "package.json"));
49003
+ const hasGit = fs25.existsSync(path27.join(cwd, ".git"));
48437
49004
  if (status.total > 0) {
48438
- print.info(`Found ${status.total} existing preseed documents`);
48439
- print.info("Run `bootspring preseed generate` to regenerate");
48440
- print.info("Run `bootspring preseed sync` to sync with codebase changes");
48441
- return;
49005
+ print.success(`Found ${status.total} existing preseed documents`);
48442
49006
  }
48443
- const preset = opts.preset;
48444
- const docs = PRESETS[preset] || PRESETS.startup;
48445
- print.info(`Preset: ${preset} (${docs.length} documents)`);
49007
+ if (hasPkg) print.success("Detected package.json");
49008
+ if (hasGit) print.success("Detected git repository");
49009
+ const contextDir = path27.join(cwd, CONTEXT_INPUT_DIR);
49010
+ let contextFileCount = 0;
49011
+ if (fs25.existsSync(contextDir)) {
49012
+ for (const folder of Object.values(CONTEXT_FOLDERS)) {
49013
+ const folderPath = path27.join(contextDir, folder.name);
49014
+ if (fs25.existsSync(folderPath)) {
49015
+ contextFileCount += fs25.readdirSync(folderPath).filter((f) => !f.startsWith(".") && !f.startsWith("README")).length;
49016
+ }
49017
+ }
49018
+ if (contextFileCount > 0) {
49019
+ print.success(`Found ${contextFileCount} context files in drop zone`);
49020
+ }
49021
+ }
49022
+ console.log("");
49023
+ console.log(`${COLORS.bold}Complete Workflow (one command):${COLORS.reset}`);
49024
+ console.log(` ${COLORS.cyan}bootspring preseed go${COLORS.reset} \u2014 runs setup \u2192 detect \u2192 generate \u2192 status`);
48446
49025
  console.log("");
48447
- console.log("This wizard will collect information about your project");
48448
- console.log("and generate foundational documents.\n");
48449
- console.log("Documents to generate:");
48450
- for (const doc of docs) {
48451
- console.log(` - ${doc}`);
49026
+ console.log(`${COLORS.bold}Step-by-Step Workflow (10 steps):${COLORS.reset}`);
49027
+ console.log("");
49028
+ console.log(" Step Command What it does");
49029
+ console.log(" \u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
49030
+ console.log(" 1 bootspring preseed start Detect environment, see this guide");
49031
+ console.log(" 2 bootspring preseed init Create folders + PRESEED_CONFIG.json");
49032
+ console.log(" 3 (drop files in context/ subfolders) Add pitch decks, notes, research");
49033
+ console.log(" 4 bootspring preseed from-codebase Auto-detect tech stack from code");
49034
+ console.log(" 5 bootspring preseed generate Generate all preseed documents");
49035
+ console.log(" 6 (edit .md files in .bootspring/preseed/) Fill in vision, audience, etc.");
49036
+ console.log(" 7 bootspring preseed status Check document completeness");
49037
+ console.log(" 8 bootspring preseed merge Combine all docs into SEED.md");
49038
+ console.log(" 9 bootspring preseed workflow start Begin review/approval workflow");
49039
+ console.log(" 10 bootspring build start Transition to build phase");
49040
+ console.log("");
49041
+ if (status.total > 0) {
49042
+ print.info("You have existing documents. Next: edit them, then run `bootspring preseed merge`");
49043
+ } else if (hasPkg) {
49044
+ print.info("Existing codebase detected. Run `bootspring preseed go` to do it all at once");
49045
+ } else {
49046
+ print.info("New project? Run `bootspring preseed go` or `bootspring preseed init` to begin");
48452
49047
  }
49048
+ });
49049
+ preseed.command("go").alias("full").description("Complete preseed workflow \u2014 setup, detect, generate, status (all in one)").option("--preset <preset>", "Preset to use (essential, startup, full, technical)", "startup").option("--force", "Overwrite existing documents").action(async (opts) => {
49050
+ print.header("Preseed \u2014 Complete Workflow");
48453
49051
  console.log("");
49052
+ const cwd = process.cwd();
49053
+ const preseedDir = path27.join(cwd, DEFAULT_OUTPUT_DIR);
49054
+ const contextDir = path27.join(cwd, CONTEXT_INPUT_DIR);
49055
+ const configPath = path27.join(preseedDir, CONFIG_FILE2);
48454
49056
  const hasPkg = fs25.existsSync(path27.join(cwd, "package.json"));
48455
49057
  const hasGit = fs25.existsSync(path27.join(cwd, ".git"));
49058
+ const hasReadme = fs25.existsSync(path27.join(cwd, "README.md"));
49059
+ console.log(`${COLORS.bold}Step 1/5: Setup${COLORS.reset}`);
49060
+ let createdCount = 0;
49061
+ if (!fs25.existsSync(preseedDir)) {
49062
+ fs25.mkdirSync(preseedDir, { recursive: true });
49063
+ createdCount++;
49064
+ }
49065
+ if (!fs25.existsSync(contextDir)) {
49066
+ fs25.mkdirSync(contextDir, { recursive: true });
49067
+ createdCount++;
49068
+ }
49069
+ for (const folder of Object.values(CONTEXT_FOLDERS)) {
49070
+ const fullPath = path27.join(contextDir, folder.name);
49071
+ if (!fs25.existsSync(fullPath)) {
49072
+ fs25.mkdirSync(fullPath, { recursive: true });
49073
+ createdCount++;
49074
+ }
49075
+ }
49076
+ const readmePath = path27.join(contextDir, "README.md");
49077
+ if (!fs25.existsSync(readmePath)) {
49078
+ fs25.writeFileSync(readmePath, generateContextReadme());
49079
+ }
49080
+ if (!fs25.existsSync(configPath)) {
49081
+ const config3 = {
49082
+ _meta: {
49083
+ version: "1.0.0",
49084
+ created: (/* @__PURE__ */ new Date()).toISOString(),
49085
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
49086
+ preset: opts.preset,
49087
+ bootspringVersion: "2.5.1",
49088
+ source: "go"
49089
+ },
49090
+ identity: { name: "", tagline: "", description: "", category: "saas" },
49091
+ problem: { statement: "", painPoints: [], currentSolutions: [], whyNow: "" },
49092
+ solution: { overview: "", keyFeatures: [], uniqueValue: "", coreCapabilities: [] },
49093
+ audience: { primary: "", segments: [], personas: [], icp: {} },
49094
+ market: { tam: null, sam: null, som: null, trends: [], growth: "" },
49095
+ competitors: { direct: [], indirect: [], positioning: "", differentiation: [] },
49096
+ business: { model: "subscription", revenueStreams: [], pricing: {}, unitEconomics: {} },
49097
+ product: { vision: "", mvpFeatures: [], futureFeatures: [], userStories: [] },
49098
+ technical: { stack: {}, architecture: "", integrations: [], constraints: [] },
49099
+ roadmap: { phases: [], milestones: [], timeline: "" },
49100
+ _sync: { lastSync: null, codebaseHash: null, linkedFiles: [], changeLog: [] }
49101
+ };
49102
+ fs25.writeFileSync(configPath, JSON.stringify(config3, null, 2));
49103
+ }
49104
+ print.success(` Folders created: ${createdCount} | Config: ${CONFIG_FILE2}`);
49105
+ console.log("");
49106
+ console.log(`${COLORS.bold}Step 2/5: Detect codebase${COLORS.reset}`);
49107
+ let projectName = path27.basename(cwd);
48456
49108
  if (hasPkg) {
48457
- print.success("Detected package.json - will use project metadata");
49109
+ try {
49110
+ const pkg = JSON.parse(fs25.readFileSync(path27.join(cwd, "package.json"), "utf-8"));
49111
+ projectName = pkg.name || projectName;
49112
+ print.success(` Project: ${projectName}`);
49113
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
49114
+ const detected = [];
49115
+ if (deps["next"]) detected.push("Next.js");
49116
+ else if (deps["react"]) detected.push("React");
49117
+ if (deps["vue"]) detected.push("Vue");
49118
+ if (deps["typescript"] || deps["ts-node"]) detected.push("TypeScript");
49119
+ if (deps["prisma"] || deps["@prisma/client"]) detected.push("Prisma");
49120
+ if (deps["tailwindcss"]) detected.push("Tailwind");
49121
+ if (deps["express"]) detected.push("Express");
49122
+ if (deps["stripe"]) detected.push("Stripe");
49123
+ if (detected.length > 0) {
49124
+ print.success(` Stack: ${detected.join(", ")}`);
49125
+ }
49126
+ } catch {
49127
+ }
49128
+ }
49129
+ if (hasGit) print.success(" Git repository detected");
49130
+ if (!hasPkg && !hasGit) print.dim(" No codebase detected (new project)");
49131
+ console.log("");
49132
+ console.log(`${COLORS.bold}Step 3/5: Update config${COLORS.reset}`);
49133
+ try {
49134
+ const config3 = JSON.parse(fs25.readFileSync(configPath, "utf-8"));
49135
+ if (!config3.identity.name) {
49136
+ config3.identity.name = projectName;
49137
+ }
49138
+ config3._meta.updated = (/* @__PURE__ */ new Date()).toISOString();
49139
+ config3._meta.preset = opts.preset;
49140
+ fs25.writeFileSync(configPath, JSON.stringify(config3, null, 2));
49141
+ print.success(` Config updated: identity.name = "${projectName}"`);
49142
+ } catch {
49143
+ print.dim(" Config unchanged");
49144
+ }
49145
+ console.log("");
49146
+ console.log(`${COLORS.bold}Step 4/5: Generate documents${COLORS.reset}`);
49147
+ const preset = opts.preset;
49148
+ const docs = PRESETS[preset] || PRESETS.startup;
49149
+ let generated = 0;
49150
+ let skipped = 0;
49151
+ for (const docType of docs) {
49152
+ const docMeta = DOCUMENT_TYPES[docType];
49153
+ const fileName = docMeta?.name ?? `${docType}.md`;
49154
+ const filePath = path27.join(preseedDir, fileName);
49155
+ if (fs25.existsSync(filePath) && !opts.force) {
49156
+ skipped++;
49157
+ continue;
49158
+ }
49159
+ const content = generateDocumentContent(docType, projectName, preset);
49160
+ fs25.writeFileSync(filePath, content);
49161
+ generated++;
49162
+ }
49163
+ if (generated > 0) print.success(` Generated: ${generated} document(s)`);
49164
+ if (skipped > 0) print.dim(` Skipped: ${skipped} (already exist, use --force to overwrite)`);
49165
+ console.log("");
49166
+ console.log(`${COLORS.bold}Step 5/5: Status${COLORS.reset}`);
49167
+ const finalStatus = getPreseedStatus();
49168
+ console.log(` Documents: ${finalStatus.total}`);
49169
+ for (const file2 of finalStatus.generated) {
49170
+ console.log(` \u2713 ${file2}`);
49171
+ }
49172
+ let contextCount = 0;
49173
+ if (fs25.existsSync(contextDir)) {
49174
+ for (const folder of Object.values(CONTEXT_FOLDERS)) {
49175
+ const folderPath = path27.join(contextDir, folder.name);
49176
+ if (fs25.existsSync(folderPath)) {
49177
+ contextCount += fs25.readdirSync(folderPath).filter((f) => !f.startsWith(".") && f !== "README.md").length;
49178
+ }
49179
+ }
48458
49180
  }
48459
- if (hasGit) {
48460
- print.success("Detected git repository - will use commit history");
49181
+ if (contextCount > 0) {
49182
+ console.log(` Context files: ${contextCount}`);
48461
49183
  }
48462
- print.info("Run `bootspring preseed setup` to create project structure");
48463
- print.info("Run `bootspring preseed generate` to generate all documents");
49184
+ console.log("");
49185
+ console.log(`${COLORS.bold}What's next:${COLORS.reset}`);
49186
+ console.log(` 1. Edit the generated .md files in ${DEFAULT_OUTPUT_DIR}/`);
49187
+ console.log(" 2. Fill in your vision, audience, market details, etc.");
49188
+ console.log(" 3. Run: bootspring preseed merge \u2192 create unified SEED.md");
49189
+ console.log(" 4. Run: bootspring build start \u2192 transition to build phase");
49190
+ console.log("");
49191
+ console.log(`${COLORS.dim}Tip: Drop pitch decks, notes, or research into ${CONTEXT_INPUT_DIR}/drop/${COLORS.reset}`);
49192
+ console.log(`${COLORS.dim} then re-run: bootspring preseed go --force${COLORS.reset}`);
48464
49193
  });
48465
49194
  preseed.command("setup").description("Create context input folders for early docs").option("--preset <preset>", "Preset to use", "startup").action(async (opts) => {
48466
49195
  print.header("Preseed Setup");
48467
49196
  const cwd = process.cwd();
48468
- const dirs = [
48469
- ".bootspring/preseed",
48470
- ".bootspring/inputs/prd",
48471
- ".bootspring/inputs/context",
48472
- ".bootspring/inputs/research"
48473
- ];
48474
- for (const dir of dirs) {
48475
- const fullPath = path27.join(cwd, dir);
49197
+ const contextDir = path27.join(cwd, CONTEXT_INPUT_DIR);
49198
+ const preseedDir = path27.join(cwd, DEFAULT_OUTPUT_DIR);
49199
+ let createdCount = 0;
49200
+ if (!fs25.existsSync(preseedDir)) {
49201
+ fs25.mkdirSync(preseedDir, { recursive: true });
49202
+ print.success(`Created ${DEFAULT_OUTPUT_DIR}/`);
49203
+ createdCount++;
49204
+ }
49205
+ if (!fs25.existsSync(contextDir)) {
49206
+ fs25.mkdirSync(contextDir, { recursive: true });
49207
+ createdCount++;
49208
+ }
49209
+ for (const folder of Object.values(CONTEXT_FOLDERS)) {
49210
+ const fullPath = path27.join(contextDir, folder.name);
48476
49211
  if (!fs25.existsSync(fullPath)) {
48477
49212
  fs25.mkdirSync(fullPath, { recursive: true });
48478
- print.success(`Created ${dir}/`);
48479
- } else {
48480
- print.dim(` Exists: ${dir}/`);
49213
+ createdCount++;
48481
49214
  }
48482
49215
  }
48483
- const configPath = path27.join(cwd, ".bootspring", "preseed-config.json");
49216
+ const readmePath = path27.join(contextDir, "README.md");
49217
+ if (!fs25.existsSync(readmePath)) {
49218
+ fs25.writeFileSync(readmePath, generateContextReadme());
49219
+ }
49220
+ const configPath = path27.join(preseedDir, CONFIG_FILE2);
48484
49221
  if (!fs25.existsSync(configPath)) {
48485
49222
  const config3 = {
48486
- preset: opts.preset,
48487
- project: {
49223
+ _meta: {
49224
+ version: "1.0.0",
49225
+ created: (/* @__PURE__ */ new Date()).toISOString(),
49226
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
49227
+ preset: opts.preset,
49228
+ bootspringVersion: "2.5.1"
49229
+ },
49230
+ identity: {
48488
49231
  name: "",
48489
49232
  tagline: "",
48490
49233
  description: "",
48491
49234
  category: "saas"
48492
49235
  },
49236
+ problem: {
49237
+ statement: "",
49238
+ painPoints: [],
49239
+ currentSolutions: [],
49240
+ whyNow: ""
49241
+ },
49242
+ solution: {
49243
+ overview: "",
49244
+ keyFeatures: [],
49245
+ uniqueValue: "",
49246
+ coreCapabilities: []
49247
+ },
48493
49248
  audience: {
48494
49249
  primary: "",
48495
- segments: []
49250
+ segments: [],
49251
+ personas: [],
49252
+ icp: {}
49253
+ },
49254
+ market: {
49255
+ tam: null,
49256
+ sam: null,
49257
+ som: null,
49258
+ trends: [],
49259
+ growth: ""
49260
+ },
49261
+ competitors: {
49262
+ direct: [],
49263
+ indirect: [],
49264
+ positioning: "",
49265
+ differentiation: []
48496
49266
  },
48497
49267
  business: {
48498
49268
  model: "subscription",
48499
- revenueStreams: []
49269
+ revenueStreams: [],
49270
+ pricing: {},
49271
+ unitEconomics: {}
49272
+ },
49273
+ product: {
49274
+ vision: "",
49275
+ mvpFeatures: [],
49276
+ futureFeatures: [],
49277
+ userStories: []
49278
+ },
49279
+ technical: {
49280
+ stack: {},
49281
+ architecture: "",
49282
+ integrations: [],
49283
+ constraints: []
49284
+ },
49285
+ roadmap: {
49286
+ phases: [],
49287
+ milestones: [],
49288
+ timeline: ""
49289
+ },
49290
+ _sync: {
49291
+ lastSync: null,
49292
+ codebaseHash: null,
49293
+ linkedFiles: [],
49294
+ changeLog: []
48500
49295
  }
48501
49296
  };
48502
49297
  fs25.writeFileSync(configPath, JSON.stringify(config3, null, 2));
48503
- print.success("Created .bootspring/preseed-config.json");
49298
+ print.success(`Created ${DEFAULT_OUTPUT_DIR}/${CONFIG_FILE2}`);
48504
49299
  }
48505
49300
  console.log("");
49301
+ print.success(`Created ${createdCount} folders`);
49302
+ console.log("");
49303
+ console.log("Context folder structure:");
49304
+ console.log(` ${CONTEXT_INPUT_DIR}/`);
49305
+ console.log(" \u2502");
49306
+ console.log(" \u2502 Universal");
49307
+ console.log(" \u251C\u2500\u2500 drop/ # Drop anything here - AI sorts it out");
49308
+ console.log(" \u2502");
49309
+ console.log(" \u2502 General");
49310
+ console.log(" \u251C\u2500\u2500 ideas/ # Rough ideas, brainstorms, notes");
49311
+ console.log(" \u251C\u2500\u2500 research/ # Market research, industry reports");
49312
+ console.log(" \u2502");
49313
+ console.log(" \u2502 Document-specific (maps to output)");
49314
+ console.log(" \u251C\u2500\u2500 vision/ # \u2192 VISION.md");
49315
+ console.log(" \u251C\u2500\u2500 audience/ # \u2192 AUDIENCE.md");
49316
+ console.log(" \u251C\u2500\u2500 market/ # \u2192 MARKET.md");
49317
+ console.log(" \u251C\u2500\u2500 competitors/ # \u2192 COMPETITORS.md");
49318
+ console.log(" \u251C\u2500\u2500 business/ # \u2192 BUSINESS_MODEL.md");
49319
+ console.log(" \u251C\u2500\u2500 prd/ # \u2192 PRD.md");
49320
+ console.log(" \u251C\u2500\u2500 technical/ # \u2192 TECHNICAL_SPEC.md");
49321
+ console.log(" \u2514\u2500\u2500 roadmap/ # \u2192 ROADMAP.md");
49322
+ console.log("");
48506
49323
  print.info("Next steps:");
48507
- console.log(" 1. Edit .bootspring/preseed-config.json with your project details");
48508
- console.log(" 2. Add any reference docs to .bootspring/inputs/");
48509
- console.log(" 3. Run `bootspring preseed generate`");
49324
+ console.log(" 1. (Optional) Drop files in context folders (e.g., vision/ for VISION.md sources)");
49325
+ console.log(" 2. Run `bootspring preseed generate` to create all documents");
49326
+ console.log(" 3. Edit the generated .md files, then run `bootspring preseed merge`");
49327
+ console.log("");
49328
+ console.log(" Or run `bootspring preseed go` to do it all in one command.");
48510
49329
  });
48511
49330
  preseed.command("generate").description("Generate or regenerate all preseed documents").option("--preset <preset>", "Preset to use", "startup").option("--force", "Overwrite existing documents").action(async (opts) => {
48512
49331
  print.header("Preseed Generate");
48513
49332
  const cwd = process.cwd();
48514
49333
  const preseedDir = ensurePreseedDir();
48515
- const configPath = path27.join(cwd, ".bootspring", "preseed-config.json");
49334
+ const configPath = path27.join(preseedDir, CONFIG_FILE2);
48516
49335
  let config3 = {};
49336
+ let projectName = path27.basename(cwd);
48517
49337
  if (fs25.existsSync(configPath)) {
48518
49338
  try {
48519
49339
  config3 = JSON.parse(fs25.readFileSync(configPath, "utf-8"));
48520
49340
  print.success("Loaded preseed config");
49341
+ const identity = config3.identity;
49342
+ if (identity?.name) {
49343
+ projectName = identity.name;
49344
+ }
48521
49345
  } catch {
48522
- print.warning("Could not parse preseed-config.json, using defaults");
49346
+ print.warning("Could not parse PRESEED_CONFIG.json, using defaults");
48523
49347
  }
48524
49348
  }
48525
- const preset = config3.preset || opts.preset;
49349
+ if (projectName === path27.basename(cwd)) {
49350
+ const pkgPath = path27.join(cwd, "package.json");
49351
+ if (fs25.existsSync(pkgPath)) {
49352
+ try {
49353
+ const pkg = JSON.parse(fs25.readFileSync(pkgPath, "utf-8"));
49354
+ projectName = pkg.name || projectName;
49355
+ } catch {
49356
+ }
49357
+ }
49358
+ }
49359
+ const meta3 = config3._meta;
49360
+ const preset = meta3?.preset || opts.preset;
48526
49361
  const docs = PRESETS[preset] || PRESETS.startup;
48527
- const projectName = config3.project?.name || path27.basename(cwd);
48528
- const date7 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
48529
49362
  print.info(`Generating ${docs.length} documents for preset: ${preset}`);
48530
49363
  console.log("");
48531
49364
  for (const docType of docs) {
48532
- const filePath = path27.join(preseedDir, `${docType}.md`);
49365
+ const docMeta = DOCUMENT_TYPES[docType];
49366
+ const fileName = docMeta?.name ?? `${docType}.md`;
49367
+ const filePath = path27.join(preseedDir, fileName);
48533
49368
  if (fs25.existsSync(filePath) && !opts.force) {
48534
- print.dim(` Skipped: ${docType}.md (exists, use --force to overwrite)`);
49369
+ print.dim(` Skipped: ${fileName} (exists, use --force to overwrite)`);
48535
49370
  continue;
48536
49371
  }
48537
- const content = `# ${projectName} - ${docType.charAt(0).toUpperCase() + docType.slice(1)}
48538
-
48539
- **Generated:** ${date7}
48540
- **Status:** Draft
48541
- **Source:** Preseed (${preset})
48542
-
48543
- ## Overview
48544
-
48545
- TODO: Add ${docType} details for ${projectName}.
48546
-
48547
- ---
48548
- *Generated by Bootspring Preseed*
48549
- `;
49372
+ const content = generateDocumentContent(docType, projectName, preset);
48550
49373
  fs25.writeFileSync(filePath, content);
48551
- print.success(`Generated: ${docType}.md`);
49374
+ print.success(`Generated: ${fileName}`);
48552
49375
  }
48553
49376
  console.log("");
48554
- print.info("Documents generated in .bootspring/preseed/");
49377
+ print.info(`Documents generated in ${DEFAULT_OUTPUT_DIR}/`);
48555
49378
  print.info("Run `bootspring preseed sync` to push to cloud");
48556
49379
  });
48557
49380
  preseed.command("sync").description("Sync preseed documents with cloud dashboard").option("--push", "Push local documents to cloud").option("--pull", "Pull documents from cloud").action(async (opts) => {
@@ -48620,6 +49443,19 @@ TODO: Add ${docType} details for ${projectName}.
48620
49443
  const status = getPreseedStatus();
48621
49444
  console.log(` Documents: ${status.total}`);
48622
49445
  console.log(` Config: ${status.hasConfig ? "found" : "not found"}`);
49446
+ const contextDir = path27.join(process.cwd(), CONTEXT_INPUT_DIR);
49447
+ if (fs25.existsSync(contextDir)) {
49448
+ let contextCount = 0;
49449
+ for (const folder of Object.values(CONTEXT_FOLDERS)) {
49450
+ const folderPath = path27.join(contextDir, folder.name);
49451
+ if (fs25.existsSync(folderPath)) {
49452
+ contextCount += fs25.readdirSync(folderPath).filter((f) => !f.startsWith(".") && f !== "README.md").length;
49453
+ }
49454
+ }
49455
+ console.log(` Context: ${contextCount} file(s) in context folders`);
49456
+ } else {
49457
+ console.log(" Context: not set up (run `bootspring preseed setup`)");
49458
+ }
48623
49459
  if (status.total > 0) {
48624
49460
  console.log("\n Generated files:");
48625
49461
  for (const file2 of status.generated) {
@@ -48658,34 +49494,23 @@ TODO: Add ${docType} details for ${projectName}.
48658
49494
  } catch {
48659
49495
  }
48660
49496
  }
48661
- const date7 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
48662
- const docs = ["vision", "roadmap"];
49497
+ const docs = ["vision", "prd", "roadmap"];
48663
49498
  if (hasReadme) docs.push("market");
48664
49499
  print.info(`Generating ${docs.length} documents from codebase context`);
48665
49500
  for (const docType of docs) {
48666
- const filePath = path27.join(preseedDir, `${docType}.md`);
49501
+ const docMeta = DOCUMENT_TYPES[docType];
49502
+ const fileName = docMeta?.name ?? `${docType}.md`;
49503
+ const filePath = path27.join(preseedDir, fileName);
48667
49504
  if (fs25.existsSync(filePath) && !opts.force) {
48668
- print.dim(` Skipped: ${docType}.md (exists)`);
49505
+ print.dim(` Skipped: ${fileName} (exists)`);
48669
49506
  continue;
48670
49507
  }
48671
- const content = `# ${projectName} - ${docType.charAt(0).toUpperCase() + docType.slice(1)}
48672
-
48673
- **Generated:** ${date7}
48674
- **Status:** Draft
48675
- **Source:** from-codebase
48676
-
48677
- ## Overview
48678
-
48679
- TODO: Add ${docType} details derived from ${projectName} codebase.
48680
-
48681
- ---
48682
- *Generated by Bootspring Preseed (from-codebase)*
48683
- `;
49508
+ const content = generateDocumentContent(docType, projectName, "from-codebase");
48684
49509
  fs25.writeFileSync(filePath, content);
48685
- print.success(`Generated: ${docType}.md`);
49510
+ print.success(`Generated: ${fileName}`);
48686
49511
  }
48687
49512
  console.log("");
48688
- print.info("Review and edit generated documents in .bootspring/preseed/");
49513
+ print.info(`Review and edit generated documents in ${DEFAULT_OUTPUT_DIR}/`);
48689
49514
  });
48690
49515
  preseed.command("export").description("Export preseed documents as JSON").option("--format <format>", "Output format (json, yaml)", "json").action(() => {
48691
49516
  const status = getPreseedStatus();
@@ -48693,7 +49518,7 @@ TODO: Add ${docType} details derived from ${projectName} codebase.
48693
49518
  print.warning("No preseed documents to export");
48694
49519
  return;
48695
49520
  }
48696
- const preseedDir = path27.join(process.cwd(), ".bootspring", "preseed");
49521
+ const preseedDir = path27.join(process.cwd(), DEFAULT_OUTPUT_DIR);
48697
49522
  const docs = {};
48698
49523
  for (const file2 of status.generated) {
48699
49524
  const content = fs25.readFileSync(path27.join(preseedDir, file2), "utf-8");
@@ -48701,8 +49526,8 @@ TODO: Add ${docType} details derived from ${projectName} codebase.
48701
49526
  }
48702
49527
  console.log(JSON.stringify({ preseed: docs, exportedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
48703
49528
  });
48704
- preseed.command("update").description("Update preseed config values").argument("<key>", "Config key (e.g., project.name)").argument("<value>", "New value").action((key, value) => {
48705
- const configPath = path27.join(process.cwd(), ".bootspring", "preseed-config.json");
49529
+ preseed.command("update").description("Update preseed config values").argument("<key>", "Config key (e.g., identity.name)").argument("<value>", "New value").action((key, value) => {
49530
+ const configPath = path27.join(process.cwd(), DEFAULT_OUTPUT_DIR, CONFIG_FILE2);
48706
49531
  if (!fs25.existsSync(configPath)) {
48707
49532
  print.error("No preseed config found. Run `bootspring preseed setup` first.");
48708
49533
  return;
@@ -48716,6 +49541,7 @@ TODO: Add ${docType} details derived from ${projectName} codebase.
48716
49541
  obj = obj[keys[i]];
48717
49542
  }
48718
49543
  obj[keys[keys.length - 1]] = value;
49544
+ config3._meta.updated = (/* @__PURE__ */ new Date()).toISOString();
48719
49545
  fs25.writeFileSync(configPath, JSON.stringify(config3, null, 2));
48720
49546
  print.success(`Updated ${key} = ${value}`);
48721
49547
  } catch {
@@ -48742,7 +49568,7 @@ TODO: Add ${docType} details derived from ${projectName} codebase.
48742
49568
  });
48743
49569
  preseed.command("merge").description("Merge preseed documents into a single SEED.md").option("--output <path>", "Output path", "SEED.md").action((opts) => {
48744
49570
  print.header("Preseed Merge");
48745
- const preseedDir = path27.join(process.cwd(), ".bootspring", "preseed");
49571
+ const preseedDir = path27.join(process.cwd(), DEFAULT_OUTPUT_DIR);
48746
49572
  const status = getPreseedStatus();
48747
49573
  if (status.total === 0) {
48748
49574
  print.warning("No preseed documents to merge");
@@ -48759,10 +49585,16 @@ TODO: Add ${docType} details derived from ${projectName} codebase.
48759
49585
  print.success(`Merged ${status.total} documents into ${opts.output}`);
48760
49586
  });
48761
49587
  preseed.command("doc").description("View or manage a specific preseed document").argument("<name>", "Document name (e.g., vision, market, roadmap)").action((name) => {
48762
- const preseedDir = path27.join(process.cwd(), ".bootspring", "preseed");
48763
- const filePath = path27.join(preseedDir, `${name}.md`);
49588
+ const preseedDir = path27.join(process.cwd(), DEFAULT_OUTPUT_DIR);
49589
+ let filePath = path27.join(preseedDir, `${name}.md`);
49590
+ if (!fs25.existsSync(filePath)) {
49591
+ const docType = DOCUMENT_TYPES[name];
49592
+ if (docType) {
49593
+ filePath = path27.join(preseedDir, docType.name);
49594
+ }
49595
+ }
48764
49596
  if (!fs25.existsSync(filePath)) {
48765
- print.error(`Document not found: ${name}.md`);
49597
+ print.error(`Document not found: ${name}`);
48766
49598
  const status = getPreseedStatus();
48767
49599
  if (status.total > 0) {
48768
49600
  print.info("Available: " + status.generated.map((f) => f.replace(".md", "")).join(", "));
@@ -50706,29 +51538,6 @@ var SEED_FOLDERS = [
50706
51538
  ".bootspring/config"
50707
51539
  ];
50708
51540
  var VALID_PRESETS = ["minimal", "standard", "full", "startup", "api"];
50709
- function isExistingCodebase(projectRoot) {
50710
- const indicators = [
50711
- "package.json",
50712
- "Cargo.toml",
50713
- "go.mod",
50714
- "requirements.txt",
50715
- "pyproject.toml",
50716
- "Gemfile",
50717
- "pom.xml",
50718
- "build.gradle",
50719
- "composer.json",
50720
- ".git"
50721
- ];
50722
- const srcDirs = ["src", "lib", "app", "pages", "components"];
50723
- for (const indicator of indicators) {
50724
- if (fs33.existsSync(path35.join(projectRoot, indicator))) return true;
50725
- }
50726
- for (const dir of srcDirs) {
50727
- const dirPath = path35.join(projectRoot, dir);
50728
- if (fs33.existsSync(dirPath) && fs33.statSync(dirPath).isDirectory()) return true;
50729
- }
50730
- return false;
50731
- }
50732
51541
  function createSeedFolders(projectRoot) {
50733
51542
  let dirsCreated = 0;
50734
51543
  for (const folder of SEED_FOLDERS) {
@@ -50823,8 +51632,16 @@ function registerSeedCommand(program3) {
50823
51632
  return;
50824
51633
  }
50825
51634
  print.info(`Preset: ${opts.preset}`);
50826
- print.info("Run the full CLI for interactive questionnaire");
50827
- print.dim("This monorepo command provides the seed subcommand structure");
51635
+ console.log("");
51636
+ print.info("To generate preseed documents and then create SEED.md, run:");
51637
+ console.log("");
51638
+ console.log(" bootspring preseed go # Complete workflow (setup + detect + generate)");
51639
+ console.log(" bootspring preseed merge # Combine preseed docs into SEED.md");
51640
+ console.log("");
51641
+ print.dim("Or run each step individually:");
51642
+ console.log(" bootspring preseed init # Create preseed folder structure");
51643
+ console.log(" bootspring preseed generate # Generate preseed document templates");
51644
+ console.log(" bootspring preseed merge # Merge into SEED.md");
50828
51645
  });
50829
51646
  seed.command("generate").description("Ingest input files and generate documents").action(() => {
50830
51647
  print.header("Seed Generate");
@@ -50857,7 +51674,18 @@ function registerSeedCommand(program3) {
50857
51674
  console.log(` ${cat}: ${count > 0 ? `${count} files` : "none"}`);
50858
51675
  }
50859
51676
  console.log("");
50860
- print.info("Process files through the full CLI for document generation");
51677
+ const totalFiles = Object.values(counts).reduce((a, b) => a + b, 0);
51678
+ if (totalFiles === 0) {
51679
+ print.info("No input files found. You can:");
51680
+ console.log(" 1. Drop files into .bootspring/inputs/ subfolders");
51681
+ console.log(" 2. Or use the preseed workflow instead:");
51682
+ console.log("");
51683
+ console.log(" bootspring preseed go # Complete preseed workflow");
51684
+ } else {
51685
+ print.success(`Found ${totalFiles} input file(s)`);
51686
+ print.info("Next: bootspring preseed generate # Generate preseed documents");
51687
+ print.info("Then: bootspring seed synthesize # Merge into SEED.md");
51688
+ }
50861
51689
  });
50862
51690
  seed.command("scaffold").description("Generate project structure from SEED.md").option("--preset <preset>", "Use preset instead of SEED.md").option("--from-config", "Use bootspring.config.js instead of SEED.md").option("--dry-run", "Show plan without creating files").option("--yes", "Skip confirmation prompt").action((opts) => {
50863
51691
  print.header("Seed Scaffold");
@@ -50898,9 +51726,11 @@ function registerSeedCommand(program3) {
50898
51726
  } else {
50899
51727
  print.dim("bootspring.config.js not found");
50900
51728
  }
50901
- console.log("\nCommands:");
50902
- console.log(" bootspring seed init # Create SEED.md");
50903
- console.log(" bootspring seed scaffold # Generate project structure");
51729
+ console.log("\nComplete Workflow:");
51730
+ console.log(" bootspring preseed go # Step 1: Generate preseed documents");
51731
+ console.log(" (edit .md files) # Step 2: Fill in your project details");
51732
+ console.log(" bootspring seed synthesize # Step 3: Merge into SEED.md");
51733
+ console.log(" bootspring build start # Step 4: Start building");
50904
51734
  });
50905
51735
  seed.command("export").description("Export seed config as JSON/YAML").option("--format <format>", "Output format: json, yaml", "json").option("--output <file>", "Write to file instead of stdout").action((opts) => {
50906
51736
  print.header("Seed Export");
@@ -50932,8 +51762,13 @@ function registerSeedCommand(program3) {
50932
51762
  const seedPath = path35.join(projectRoot, "SEED.md");
50933
51763
  if (!fs33.existsSync(preseedDir)) {
50934
51764
  print.error("No preseed documents found");
50935
- const suggestion = isExistingCodebase(projectRoot) ? "bootspring preseed codebase" : "bootspring preseed start";
50936
- print.info(`Run ${suggestion} first`);
51765
+ console.log("");
51766
+ print.info("Run the complete preseed workflow first:");
51767
+ console.log("");
51768
+ console.log(" bootspring preseed go # Complete workflow (setup + detect + generate)");
51769
+ console.log(" bootspring seed synthesize # Then re-run this command");
51770
+ console.log("");
51771
+ print.dim("Or for existing codebases: bootspring preseed from-codebase");
50937
51772
  return;
50938
51773
  }
50939
51774
  const validDocs = [
@@ -50948,20 +51783,28 @@ function registerSeedCommand(program3) {
50948
51783
  ];
50949
51784
  const preseedFiles = fs33.readdirSync(preseedDir).filter((f) => validDocs.includes(f));
50950
51785
  if (preseedFiles.length === 0) {
50951
- print.error("No preseed documents found");
50952
- print.info('Run "bootspring preseed init" first');
51786
+ print.error("No preseed documents found in .bootspring/preseed/");
51787
+ print.info('Run "bootspring preseed go" to generate them');
50953
51788
  return;
50954
51789
  }
50955
- console.log(`Found ${preseedFiles.length} preseed documents:`);
50956
- for (const file2 of preseedFiles) {
50957
- print.success(file2);
50958
- }
50959
51790
  if (fs33.existsSync(seedPath) && !opts.force) {
50960
51791
  print.warning("SEED.md already exists");
50961
51792
  print.info("Use --force to overwrite");
50962
51793
  return;
50963
51794
  }
50964
- print.info("Synthesis runs through the full CLI for complete SEED.md generation");
51795
+ console.log(`Found ${preseedFiles.length} preseed documents:`);
51796
+ const sections = [];
51797
+ for (const file2 of preseedFiles) {
51798
+ const content = fs33.readFileSync(path35.join(preseedDir, file2), "utf-8");
51799
+ sections.push(content);
51800
+ print.success(` ${file2}`);
51801
+ }
51802
+ const merged = sections.join("\n\n---\n\n");
51803
+ fs33.writeFileSync(seedPath, merged);
51804
+ console.log("");
51805
+ print.success(`Created SEED.md (${preseedFiles.length} documents merged)`);
51806
+ console.log("");
51807
+ print.info("Next: bootspring build start # Transition to build phase");
50965
51808
  });
50966
51809
  seed.command("update").description("Re-run questionnaire, update SEED.md").option("--preset <preset>", "Questionnaire preset").action((opts) => {
50967
51810
  print.header("Seed Update");
@@ -50974,12 +51817,38 @@ function registerSeedCommand(program3) {
50974
51817
  }
50975
51818
  print.info("Update runs through the full CLI for interactive questionnaire");
50976
51819
  });
50977
- seed.command("build").description("Build from seed docs").option("--loop", "Start continuous build loop").option("--iterations <n>", "Max iterations for loop", "50").action((opts) => {
51820
+ seed.command("build").description("Build from seed docs").option("--loop", "Start continuous build loop").option("--iterations <n>", "Max iterations for loop", "50").action(() => {
50978
51821
  print.header("Seed Build");
50979
- if (opts.loop) {
50980
- print.info(`Starting build loop (max ${opts.iterations} iterations)`);
51822
+ const projectRoot = process.cwd();
51823
+ const seedPath = path35.join(projectRoot, "SEED.md");
51824
+ const preseedDir = path35.join(projectRoot, ".bootspring", "preseed");
51825
+ const hasPreseedDocs = fs33.existsSync(preseedDir) && fs33.readdirSync(preseedDir).filter((f) => f.endsWith(".md")).length > 0;
51826
+ if (!fs33.existsSync(seedPath) && !hasPreseedDocs) {
51827
+ print.error("No SEED.md or preseed documents found");
51828
+ console.log("");
51829
+ print.info("Complete workflow to get here:");
51830
+ console.log("");
51831
+ console.log(" Step 1: bootspring preseed go # Generate preseed documents");
51832
+ console.log(" Step 2: (edit the generated .md files in .bootspring/preseed/)");
51833
+ console.log(" Step 3: bootspring seed synthesize # Merge into SEED.md");
51834
+ console.log(" Step 4: bootspring build start # Start building");
51835
+ return;
50981
51836
  }
50982
- print.info("Build runs through the build command pipeline");
51837
+ if (hasPreseedDocs && !fs33.existsSync(seedPath)) {
51838
+ print.info(`Found ${fs33.readdirSync(preseedDir).filter((f) => f.endsWith(".md")).length} preseed documents but no SEED.md`);
51839
+ console.log("");
51840
+ print.info("Next steps:");
51841
+ console.log(" 1. bootspring seed synthesize # Merge preseed docs into SEED.md");
51842
+ console.log(" 2. bootspring build start # Start building");
51843
+ return;
51844
+ }
51845
+ print.success("SEED.md found");
51846
+ console.log("");
51847
+ print.info("To start building, run:");
51848
+ console.log("");
51849
+ console.log(" bootspring build start # Initialize build from seed documents");
51850
+ console.log(" bootspring build next # Get the next task");
51851
+ console.log(" bootspring build status # Check progress");
50983
51852
  });
50984
51853
  seed.action(() => {
50985
51854
  seed.outputHelp();