@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 +1016 -147
- package/dist/core/index.d.ts +24 -2
- package/dist/core.js +62 -13
- package/dist/mcp-server.js +62 -13
- package/package.json +1 -1
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.
|
|
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
|
-
|
|
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:
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
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
|
-
|
|
5726
|
-
"
|
|
5727
|
-
"
|
|
5728
|
-
"
|
|
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
|
-
|
|
48410
|
-
|
|
48411
|
-
|
|
48412
|
-
|
|
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(),
|
|
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(),
|
|
48423
|
-
const configFile = path27.join(
|
|
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.
|
|
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
|
-
|
|
48444
|
-
|
|
48445
|
-
|
|
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(
|
|
48448
|
-
console.log("
|
|
48449
|
-
console.log("
|
|
48450
|
-
|
|
48451
|
-
|
|
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
|
-
|
|
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 (
|
|
48460
|
-
|
|
49181
|
+
if (contextCount > 0) {
|
|
49182
|
+
console.log(` Context files: ${contextCount}`);
|
|
48461
49183
|
}
|
|
48462
|
-
|
|
48463
|
-
|
|
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
|
|
48469
|
-
|
|
48470
|
-
|
|
48471
|
-
|
|
48472
|
-
|
|
48473
|
-
|
|
48474
|
-
|
|
48475
|
-
|
|
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
|
-
|
|
48479
|
-
} else {
|
|
48480
|
-
print.dim(` Exists: ${dir}/`);
|
|
49213
|
+
createdCount++;
|
|
48481
49214
|
}
|
|
48482
49215
|
}
|
|
48483
|
-
const
|
|
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
|
-
|
|
48487
|
-
|
|
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(
|
|
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.
|
|
48508
|
-
console.log(" 2.
|
|
48509
|
-
console.log(" 3.
|
|
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(
|
|
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
|
|
49346
|
+
print.warning("Could not parse PRESEED_CONFIG.json, using defaults");
|
|
48523
49347
|
}
|
|
48524
49348
|
}
|
|
48525
|
-
|
|
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
|
|
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: ${
|
|
49369
|
+
print.dim(` Skipped: ${fileName} (exists, use --force to overwrite)`);
|
|
48535
49370
|
continue;
|
|
48536
49371
|
}
|
|
48537
|
-
const content =
|
|
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: ${
|
|
49374
|
+
print.success(`Generated: ${fileName}`);
|
|
48552
49375
|
}
|
|
48553
49376
|
console.log("");
|
|
48554
|
-
print.info(
|
|
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
|
|
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
|
|
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: ${
|
|
49505
|
+
print.dim(` Skipped: ${fileName} (exists)`);
|
|
48669
49506
|
continue;
|
|
48670
49507
|
}
|
|
48671
|
-
const content =
|
|
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: ${
|
|
49510
|
+
print.success(`Generated: ${fileName}`);
|
|
48686
49511
|
}
|
|
48687
49512
|
console.log("");
|
|
48688
|
-
print.info(
|
|
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(),
|
|
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.,
|
|
48705
|
-
const configPath = path27.join(process.cwd(),
|
|
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(),
|
|
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(),
|
|
48763
|
-
|
|
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}
|
|
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
|
-
|
|
50827
|
-
print.
|
|
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
|
-
|
|
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("\
|
|
50902
|
-
console.log(" bootspring
|
|
50903
|
-
console.log("
|
|
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
|
-
|
|
50936
|
-
print.info(
|
|
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
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
50980
|
-
|
|
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
|
-
|
|
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();
|