claude-launchpad 0.9.1 → 0.9.2-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -241,7 +241,7 @@ Score below threshold = exit code 1 = PR blocked.
241
241
 
242
242
  **Doctor** reads your files and runs static analysis. No API calls. No network. No cost.
243
243
 
244
- **Init** scans manifest files (package.json, go.mod, pyproject.toml, etc.), detects your stack, and generates 7 files: CLAUDE.md (with sprint reviews and memory management), TASKS.md (with deferred issues section), settings.json (with credential deny rules, sandbox enabled, bypass mode disabled, hooks including sprint review and PostCompact), .claude/.gitignore, .claudeignore, /lp-enhance skill, and language-specific rules. Formatter hooks use hardcoded safe commands only.
244
+ **Init** scans manifest files (package.json, go.mod, pyproject.toml, etc.), detects your stack, and generates 8 files: CLAUDE.md (with sprint reviews and backlog management), TASKS.md (with deferred issues section), BACKLOG.md (priority-tiered feature parking), settings.json (with credential deny rules, sandbox enabled, bypass mode disabled, hooks including sprint review and PostCompact), .claude/.gitignore, .claudeignore, /lp-enhance skill, and language-specific rules. Formatter hooks use hardcoded safe commands only.
245
245
 
246
246
  **Enhance** is a `/lp-enhance` skill installed during `init`. It runs inside your active Claude Code session - no separate process, no overhead. Claude already has your codebase context, so it produces better results than an external command.
247
247
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/dist/cli.js CHANGED
@@ -256,7 +256,12 @@ function generateClaudeMd(options, detected) {
256
256
  sections.push("", `## Session Start
257
257
  - ALWAYS read @TASKS.md first \u2014 it tracks progress across sessions
258
258
  - Check the Session Log at the bottom of TASKS.md for where we left off
259
- - Update TASKS.md as you complete work`);
259
+ - Update TASKS.md as you complete work
260
+
261
+ ## Backlog
262
+ - When a feature is discussed but deferred, add it to BACKLOG.md immediately
263
+ - Never leave future ideas only in TASKS.md or conversation \u2014 they get lost
264
+ - BACKLOG.md is the single source of truth for parked features`);
260
265
  sections.push("", `## Sprint Reviews
261
266
  When all tasks in the current sprint are complete, do a quick quality check before committing:
262
267
  - Scan changed files for dead code, debug logs, and TODO hacks
@@ -584,6 +589,20 @@ Also review .claude/settings.json hooks:
584
589
  `;
585
590
  }
586
591
 
592
+ // src/commands/init/generators/backlog.ts
593
+ function generateBacklogMd(options) {
594
+ return `# ${options.name} \u2014 Backlog
595
+
596
+ > Features discussed but deferred. Pick up when relevant.
597
+ > Priority: P0 = next sprint, P1 = soon, P2 = when relevant.
598
+
599
+ <!-- Add deferred features here. Format:
600
+ ## [P1] Feature Name
601
+ One-line description. Context for why it was deferred and when to revisit.
602
+ -->
603
+ `;
604
+ }
605
+
587
606
  // src/commands/init/index.ts
588
607
  function createInitCommand() {
589
608
  return new Command("init").description("Set up Claude Code configuration for any project").option("-n, --name <name>", "Project name").option("-y, --yes", "Accept all defaults").action(async (opts) => {
@@ -628,11 +647,14 @@ async function scaffold(root, options, detected, skipPrompts) {
628
647
  log.step("Generating configuration...");
629
648
  const claudeMd = generateClaudeMd(options, detected);
630
649
  const tasksMd = generateTasksMd(options);
650
+ const backlogMd = generateBacklogMd(options);
631
651
  const settings = generateSettings(detected);
632
652
  const claudeignore = generateClaudeignore(detected);
633
653
  await mkdir(join2(root, ".claude", "rules"), { recursive: true });
634
654
  const settingsPath = join2(root, ".claude", "settings.json");
635
655
  const mergedSettings = await mergeSettings(settingsPath, settings);
656
+ const backlogPath = join2(root, "BACKLOG.md");
657
+ const hasBacklog = await fileExists(backlogPath);
636
658
  const claudeignorePath = join2(root, ".claudeignore");
637
659
  const hasClaudeignore = await fileExists(claudeignorePath);
638
660
  const claudeGitignorePath = join2(root, ".claude", ".gitignore");
@@ -644,6 +666,9 @@ async function scaffold(root, options, detected, skipPrompts) {
644
666
  writeFile(join2(root, "TASKS.md"), tasksMd),
645
667
  writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2) + "\n")
646
668
  ];
669
+ if (!hasBacklog) {
670
+ writes.push(writeFile(backlogPath, backlogMd));
671
+ }
647
672
  if (!hasClaudeignore) {
648
673
  writes.push(writeFile(claudeignorePath, claudeignore));
649
674
  }
@@ -665,6 +690,7 @@ async function scaffold(root, options, detected, skipPrompts) {
665
690
  await Promise.all(writes);
666
691
  log.success("Generated CLAUDE.md");
667
692
  log.success("Generated TASKS.md");
693
+ if (!hasBacklog) log.success("Generated BACKLOG.md");
668
694
  log.success("Generated .claude/settings.json (schema, permissions, hooks)");
669
695
  if (!hasClaudeGitignore) log.success("Generated .claude/.gitignore");
670
696
  if (!hasClaudeignore) log.success("Generated .claudeignore");
@@ -1099,6 +1125,15 @@ import { homedir as homedir2 } from "os";
1099
1125
  async function analyzeRules(config) {
1100
1126
  const issues = [];
1101
1127
  const projectRoot = config.claudeMdPath ? dirname(config.claudeMdPath) : process.cwd();
1128
+ const hasBacklog = await fileExists(join4(projectRoot, "BACKLOG.md"));
1129
+ if (!hasBacklog) {
1130
+ issues.push({
1131
+ analyzer: "Rules",
1132
+ severity: "low",
1133
+ message: "No BACKLOG.md found \u2014 deferred features get lost in conversation history",
1134
+ fix: "Run `claude-launchpad init` or `doctor --fix` to generate one"
1135
+ });
1136
+ }
1102
1137
  const hasClaudeignore = await fileExists(join4(projectRoot, ".claudeignore"));
1103
1138
  if (!hasClaudeignore) {
1104
1139
  issues.push({
@@ -1507,6 +1542,7 @@ var FIX_TABLE = [
1507
1542
  return addClaudeMdSection(root, "## Stack", content);
1508
1543
  } },
1509
1544
  { analyzer: "Quality", match: "Session Start", fix: (root) => addClaudeMdSection(root, "## Session Start", "- ALWAYS read @TASKS.md first - it tracks progress across sessions\n- Update TASKS.md as you complete work") },
1545
+ { analyzer: "Rules", match: "No BACKLOG.md", fix: (root) => createBacklogMd(root) },
1510
1546
  { analyzer: "Rules", match: "No .claudeignore", fix: (root, detected) => createClaudeignore(root, detected) },
1511
1547
  { analyzer: "Rules", match: "No .claude/rules/", fix: (root) => createStarterRules(root) },
1512
1548
  { analyzer: "Hooks", match: "PostCompact", fix: (root) => addPostCompactHook(root) },
@@ -1712,6 +1748,22 @@ ${content}
1712
1748
  log.success(`Added "${heading}" section to CLAUDE.md`);
1713
1749
  return true;
1714
1750
  }
1751
+ async function createBacklogMd(root) {
1752
+ const backlogPath = join5(root, "BACKLOG.md");
1753
+ try {
1754
+ await access4(backlogPath);
1755
+ return false;
1756
+ } catch {
1757
+ }
1758
+ const name = root.split("/").pop() ?? "Project";
1759
+ await writeFile2(backlogPath, `# ${name} \u2014 Backlog
1760
+
1761
+ > Features discussed but deferred. Pick up when relevant.
1762
+ > Priority: P0 = next sprint, P1 = soon, P2 = when relevant.
1763
+ `);
1764
+ log.success("Generated BACKLOG.md");
1765
+ return true;
1766
+ }
1715
1767
  async function createClaudeignore(root, detected) {
1716
1768
  const ignorePath = join5(root, ".claudeignore");
1717
1769
  try {
@@ -2644,7 +2696,7 @@ function createMemoryCommand() {
2644
2696
  }
2645
2697
 
2646
2698
  // src/cli.ts
2647
- var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.9.1", "-v, --version").action(async () => {
2699
+ var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.9.2-dev.0", "-v, --version").action(async () => {
2648
2700
  const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
2649
2701
  if (hasConfig) {
2650
2702
  await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });