create-battle-plan 1.4.2 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/cli.js +52 -30
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -71,6 +71,14 @@ function ask(question) {
71
71
  });
72
72
  }
73
73
 
74
+ async function askRequired(question, errorMsg) {
75
+ while (true) {
76
+ const answer = await ask(question);
77
+ if (answer) return answer;
78
+ console.log(`${YELLOW} ${errorMsg}${RESET}`);
79
+ }
80
+ }
81
+
74
82
  // ── Interactive folder picker (raw mode) ─────────────────
75
83
 
76
84
  function getDirs(dir) {
@@ -310,8 +318,10 @@ async function main() {
310
318
  initReadline();
311
319
 
312
320
  // Question 1: Project description (one sentence — used for context, not the folder name)
313
- const projectName = await ask(`${DIM}[1/7]${RESET} ${BOLD}What's your project in one sentence?${RESET}\n> `);
314
- if (!projectName) { console.log('Project name is required.'); process.exit(1); }
321
+ const projectName = await askRequired(
322
+ `${DIM}[1/7]${RESET} ${BOLD}What's your project in one sentence?${RESET}\n> `,
323
+ 'A one-sentence description is required — even rough is fine. Try again:'
324
+ );
315
325
  console.log('');
316
326
 
317
327
  // Question 2: Short name (the actual folder slug). Default = cwd basename when sensible.
@@ -338,20 +348,21 @@ async function main() {
338
348
  );
339
349
  console.log('');
340
350
 
341
- // Question 4: Metrics
351
+ // Question 4: Metrics (optional — leave blank for journal-style projects)
342
352
  const metricsRaw = await ask(
343
- `${DIM}[4/7]${RESET} ${BOLD}What are the 3-5 key metrics you want to track?${RESET} ${DIM}(comma-separated, e.g., "outreach sent, calls booked, LOIs signed")${RESET}\n> `
353
+ `${DIM}[4/7]${RESET} ${BOLD}Any metrics to track?${RESET} ${DIM}(comma-separated, e.g., "outreach sent, calls booked, LOIs signed" — or press enter to skip)${RESET}\n> `
344
354
  );
345
- if (!metricsRaw) { console.log('At least one metric is required.'); process.exit(1); }
346
- const metrics = metricsRaw.split(',').map((m) => m.trim()).filter(Boolean);
355
+ const metrics = metricsRaw
356
+ ? metricsRaw.split(',').map((m) => m.trim()).filter(Boolean)
357
+ : [];
347
358
  console.log('');
348
359
 
349
360
  // Question 5: Domains
350
361
  const suggested = suggestDomains(projectName);
351
- const domainsRaw = await ask(
352
- `${DIM}[5/7]${RESET} ${BOLD}What domains does your work cover?${RESET} ${DIM}(comma-separated)\nSuggested based on your project: ${suggested}${RESET}\n> `
362
+ const domainsRaw = await askRequired(
363
+ `${DIM}[5/7]${RESET} ${BOLD}What domains does your work cover?${RESET} ${DIM}(comma-separated)\nSuggested based on your project: ${suggested}${RESET}\n> `,
364
+ `At least one domain is required — try the suggestions (${suggested}) or any topic area. Try again:`
353
365
  );
354
- if (!domainsRaw) { console.log('At least one domain is required.'); process.exit(1); }
355
366
  const domains = domainsRaw.split(',').map((d) => d.trim().toLowerCase()).filter(Boolean);
356
367
  console.log('');
357
368
 
@@ -444,7 +455,11 @@ _Start adding content here._
444
455
 
445
456
  console.log(`${DIM} + docs/ (${domains.length} domain${domains.length > 1 ? 's' : ''})${RESET}`);
446
457
 
447
- // Create metrics.yml
458
+ // Create metrics.yml — file always exists so scripts have a target, even if no
459
+ // metrics were declared (journal-style projects). The LLM can add metrics later.
460
+ const metricsBody = metrics.length
461
+ ? metrics.map((m) => `${metricKey(m)}: 0`).join('\n') + '\n'
462
+ : '# No metrics declared yet. Add them as `key: value` below when ready.\n';
448
463
  const metricsContent = [
449
464
  `# metrics.yml — project-wide metrics registry for ${projectName}`,
450
465
  '# The LLM updates this file FIRST in any cascade, before touching docs.',
@@ -452,16 +467,33 @@ _Start adding content here._
452
467
  '',
453
468
  `last_updated: ${today}`,
454
469
  '',
455
- ...metrics.map((m) => `${metricKey(m)}: 0`),
456
- '',
470
+ metricsBody,
457
471
  ].join('\n');
458
472
  fs.writeFileSync(path.join(targetDir, 'metrics.yml'), metricsContent);
459
- console.log(`${DIM} + metrics.yml (${metrics.length} metric${metrics.length > 1 ? 's' : ''})${RESET}`);
473
+ console.log(
474
+ `${DIM} + metrics.yml (${metrics.length === 0 ? 'no metrics yet' : `${metrics.length} metric${metrics.length > 1 ? 's' : ''}`})${RESET}`
475
+ );
476
+
477
+ // Create battle plan — conditionally include Key Metrics section
478
+ const metricsSection = metrics.length
479
+ ? `## Key Metrics
480
+
481
+ | Metric | Target | Current |
482
+ |--------|--------|---------|
483
+ ${metrics.map((m) => `| ${m} | _set target_ | **0** (→ metrics.yml#${metricKey(m)}) |`).join('\n')}
460
484
 
461
- // Create battle plan
462
- const metricsTable = metrics
463
- .map((m) => `| ${m} | _set target_ | **0** (→ metrics.yml#${metricKey(m)}) |`)
464
- .join('\n');
485
+ ---
486
+
487
+ `
488
+ : '';
489
+
490
+ const tldr = metrics.length
491
+ ? `${projectName} — just initialized. Time horizon: ${horizon || 'not set'}. All metrics at 0. First priority: fill in the battle plan with real tasks and targets.`
492
+ : `${projectName} — just initialized. Time horizon: ${horizon || 'not set'}. No metrics tracked yet (journal-style project). First priority: fill in the battle plan with real tasks.`;
493
+
494
+ const firstPriority = metrics.length
495
+ ? '- [ ] Set targets for each metric\n- [ ] Fill in this week\'s tasks\n- [ ] Record any existing conversations in external-insights.md'
496
+ : '- [ ] Fill in this week\'s tasks\n- [ ] Record any existing conversations in external-insights.md';
465
497
 
466
498
  fs.writeFileSync(
467
499
  path.join(targetDir, 'docs', 'battle-plan.md'),
@@ -472,7 +504,7 @@ _Start adding content here._
472
504
  **Role:** source-of-truth
473
505
  **Compression:** chronological
474
506
 
475
- **TL;DR:** ${projectName} — just initialized. Time horizon: ${horizon || 'not set'}. All metrics at 0. First priority: fill in the battle plan with real tasks and targets.
507
+ **TL;DR:** ${tldr}
476
508
 
477
509
  ---
478
510
 
@@ -485,19 +517,9 @@ _Start adding content here._
485
517
 
486
518
  ---
487
519
 
488
- ## Key Metrics
489
-
490
- | Metric | Target | Current |
491
- |--------|--------|---------|
492
- ${metricsTable}
493
-
494
- ---
495
-
496
- ## Today's Priorities
520
+ ${metricsSection}## Today's Priorities
497
521
 
498
- - [ ] Set targets for each metric
499
- - [ ] Fill in this week's tasks
500
- - [ ] Record any existing conversations in external-insights.md
522
+ ${firstPriority}
501
523
 
502
524
  ---
503
525
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-battle-plan",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "Scaffold a Battle Plan project — a markdown-based context system for LLM-powered project management",
5
5
  "bin": {
6
6
  "create-battle-plan": "./bin/cli.js"