claude-launchpad 1.16.0 → 1.17.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.
Files changed (44) hide show
  1. package/dist/{chunk-IPGNXDJF.js → chunk-IIOY56ZE.js} +2 -2
  2. package/dist/{chunk-DLDVXHI3.js → chunk-JKDFOKHD.js} +2 -2
  3. package/dist/{chunk-U2TFIUGE.js → chunk-KYGWNN5F.js} +38 -7
  4. package/dist/chunk-KYGWNN5F.js.map +1 -0
  5. package/dist/{chunk-IDH3M4EI.js → chunk-MRW63LDL.js} +6 -1
  6. package/dist/chunk-MRW63LDL.js.map +1 -0
  7. package/dist/{chunk-LCKV24Q3.js → chunk-ROQI7RKM.js} +4 -4
  8. package/dist/{chunk-MX3T2VEX.js → chunk-ULECXQFX.js} +3 -3
  9. package/dist/{chunk-7KB5YGQZ.js → chunk-YLIV5WBW.js} +2 -2
  10. package/dist/cli.js +69 -29
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/memory/server.js +5 -5
  13. package/dist/{context-3GHG7KW6.js → context-K5B43NEI.js} +7 -7
  14. package/dist/{doctor-EKGJ2YAO.js → doctor-ESIQYNE4.js} +5 -5
  15. package/dist/{install-543ZKMXX.js → install-VREFJNLF.js} +9 -7
  16. package/dist/install-VREFJNLF.js.map +1 -0
  17. package/dist/{pull-ULSZEVCR.js → pull-H6ARY6DG.js} +9 -9
  18. package/dist/{push-JXCWX4NY.js → push-JDHT6AMD.js} +9 -9
  19. package/dist/{require-deps-AEDO5YRM.js → require-deps-GVBWF5PB.js} +3 -3
  20. package/dist/{stats-63L7C24W.js → stats-TWIVFA4I.js} +8 -8
  21. package/dist/{sync-QTJ6BXQ4.js → sync-WG7OOWOX.js} +5 -5
  22. package/dist/{sync-clean-OJEK4XH4.js → sync-clean-GQUFTYG2.js} +3 -3
  23. package/dist/{sync-status-EAX527SC.js → sync-status-B3DKLET4.js} +9 -9
  24. package/dist/{tui-BS4XXLOC.js → tui-ZINEA7TI.js} +166 -47
  25. package/dist/tui-ZINEA7TI.js.map +1 -0
  26. package/package.json +1 -1
  27. package/dist/chunk-IDH3M4EI.js.map +0 -1
  28. package/dist/chunk-U2TFIUGE.js.map +0 -1
  29. package/dist/install-543ZKMXX.js.map +0 -1
  30. package/dist/tui-BS4XXLOC.js.map +0 -1
  31. /package/dist/{chunk-IPGNXDJF.js.map → chunk-IIOY56ZE.js.map} +0 -0
  32. /package/dist/{chunk-DLDVXHI3.js.map → chunk-JKDFOKHD.js.map} +0 -0
  33. /package/dist/{chunk-LCKV24Q3.js.map → chunk-ROQI7RKM.js.map} +0 -0
  34. /package/dist/{chunk-MX3T2VEX.js.map → chunk-ULECXQFX.js.map} +0 -0
  35. /package/dist/{chunk-7KB5YGQZ.js.map → chunk-YLIV5WBW.js.map} +0 -0
  36. /package/dist/{context-3GHG7KW6.js.map → context-K5B43NEI.js.map} +0 -0
  37. /package/dist/{doctor-EKGJ2YAO.js.map → doctor-ESIQYNE4.js.map} +0 -0
  38. /package/dist/{pull-ULSZEVCR.js.map → pull-H6ARY6DG.js.map} +0 -0
  39. /package/dist/{push-JXCWX4NY.js.map → push-JDHT6AMD.js.map} +0 -0
  40. /package/dist/{require-deps-AEDO5YRM.js.map → require-deps-GVBWF5PB.js.map} +0 -0
  41. /package/dist/{stats-63L7C24W.js.map → stats-TWIVFA4I.js.map} +0 -0
  42. /package/dist/{sync-QTJ6BXQ4.js.map → sync-WG7OOWOX.js.map} +0 -0
  43. /package/dist/{sync-clean-OJEK4XH4.js.map → sync-clean-GQUFTYG2.js.map} +0 -0
  44. /package/dist/{sync-status-EAX527SC.js.map → sync-status-B3DKLET4.js.map} +0 -0
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  cwdRequire
4
- } from "./chunk-7KB5YGQZ.js";
4
+ } from "./chunk-YLIV5WBW.js";
5
5
  import {
6
6
  __export
7
- } from "./chunk-U2TFIUGE.js";
7
+ } from "./chunk-KYGWNN5F.js";
8
8
 
9
9
  // src/commands/memory/storage/migrations/001-initial.ts
10
10
  var initial_exports = {};
@@ -222,4 +222,4 @@ function migrate(db) {
222
222
  export {
223
223
  migrate
224
224
  };
225
- //# sourceMappingURL=chunk-MX3T2VEX.js.map
225
+ //# sourceMappingURL=chunk-ULECXQFX.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  log
4
- } from "./chunk-U2TFIUGE.js";
4
+ } from "./chunk-KYGWNN5F.js";
5
5
 
6
6
  // src/commands/memory/utils/require-deps.ts
7
7
  import { createRequire } from "module";
@@ -44,4 +44,4 @@ export {
44
44
  cwdRequire,
45
45
  requireMemoryDeps
46
46
  };
47
- //# sourceMappingURL=chunk-7KB5YGQZ.js.map
47
+ //# sourceMappingURL=chunk-YLIV5WBW.js.map
package/dist/cli.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readSyncConfig
4
- } from "./chunk-IPGNXDJF.js";
4
+ } from "./chunk-IIOY56ZE.js";
5
5
  import {
6
6
  BACKLOG_CONTENT,
7
7
  ENHANCE_SKILL_VERSION,
8
8
  FORCE_PUSH_ERE,
9
+ HOOKS_RULE_VERSION,
9
10
  LP_STUB_OPEN,
10
11
  OFF_LIMITS_CONTENT,
11
12
  SESSION_START_CONTENT,
@@ -41,7 +42,7 @@ import {
41
42
  sprintReviewsContent,
42
43
  writeSprintHygieneScripts,
43
44
  writeWorkflowCheckScript
44
- } from "./chunk-U2TFIUGE.js";
45
+ } from "./chunk-KYGWNN5F.js";
45
46
 
46
47
  // src/cli.ts
47
48
  import { Command as Command5 } from "commander";
@@ -650,6 +651,7 @@ async function readHooksFromFile(settingsPath) {
650
651
  type: h.type ?? "command",
651
652
  matcher,
652
653
  command: h.command,
654
+ async: h.async === true,
653
655
  timeout: h.timeout
654
656
  });
655
657
  }
@@ -659,6 +661,7 @@ async function readHooksFromFile(settingsPath) {
659
661
  type: g.type ?? "command",
660
662
  matcher,
661
663
  command: g.command,
664
+ async: g.async === true,
662
665
  timeout: g.timeout
663
666
  });
664
667
  }
@@ -1154,6 +1157,19 @@ async function analyzeRules(config) {
1154
1157
  fix: "Run `doctor --fix` to generate it"
1155
1158
  });
1156
1159
  }
1160
+ if (hasHooksRule) {
1161
+ const hContent = await readFile2(join4(projectRoot, ".claude", "rules", "hooks.md"), "utf-8").catch(() => "");
1162
+ const hMatch = hContent.match(/<!-- lp-hooks-version: (\d+) -->/);
1163
+ const hVersion = hMatch ? parseInt(hMatch[1], 10) : null;
1164
+ if (hVersion !== null && hVersion < HOOKS_RULE_VERSION) {
1165
+ issues.push({
1166
+ analyzer: "Rules",
1167
+ severity: "low",
1168
+ message: `hooks.md rule is outdated (v${hVersion}, latest v${HOOKS_RULE_VERSION})`,
1169
+ fix: "Run `doctor --fix` to update it"
1170
+ });
1171
+ }
1172
+ }
1157
1173
  const verificationPath = join4(
1158
1174
  projectRoot,
1159
1175
  ".claude",
@@ -1706,15 +1722,26 @@ async function analyzeMemory(config, projectRoot) {
1706
1722
  fix: "Run `doctor --fix` to add a SessionEnd hook that pushes memories automatically"
1707
1723
  });
1708
1724
  }
1709
- const hasNonNohupPush = config.hooks.some(
1710
- (h) => h.event === "SessionEnd" && h.command?.includes("memory push") && !h.command.includes("nohup")
1725
+ const hasKillablePush = config.hooks.some(
1726
+ (h) => h.event === "SessionEnd" && h.command?.includes("memory push") && !h.command.includes("nohup") && h.async !== true
1711
1727
  );
1712
- if (hasNonNohupPush) {
1728
+ if (hasKillablePush) {
1713
1729
  issues.push({
1714
1730
  analyzer: "Memory",
1715
1731
  severity: "high",
1716
- message: "SessionEnd push hook is not nohup-wrapped \u2014 Claude Code cancels it on exit before the push completes",
1717
- fix: "Run `doctor --fix` to upgrade the hook to a nohup-wrapped push"
1732
+ message: "SessionEnd push hook is neither async nor detached \u2014 Claude Code kills it on exit before the push completes",
1733
+ fix: "Run `doctor --fix` to upgrade it to the native async form"
1734
+ });
1735
+ }
1736
+ const hasLegacyNohupPush = config.hooks.some(
1737
+ (h) => h.event === "SessionEnd" && h.command?.includes("memory push") && h.command.includes("nohup")
1738
+ );
1739
+ if (hasLegacyNohupPush) {
1740
+ issues.push({
1741
+ analyzer: "Memory",
1742
+ severity: "low",
1743
+ message: "SessionEnd push hook uses the legacy nohup wrapper \u2014 the native async: true form is canonical",
1744
+ fix: "Run `doctor --fix` to upgrade it"
1718
1745
  });
1719
1746
  }
1720
1747
  }
@@ -1734,7 +1761,10 @@ async function analyzeMemory(config, projectRoot) {
1734
1761
  const high = issues.filter((i) => i.severity === "high").length;
1735
1762
  const medium = issues.filter((i) => i.severity === "medium").length;
1736
1763
  const low = issues.filter((i) => i.severity === "low").length;
1737
- const score = Math.max(0, 100 - (critical * 40 + high * 20 + medium * 10 + low * 5));
1764
+ const score = Math.max(
1765
+ 0,
1766
+ 100 - (critical * 40 + high * 20 + medium * 10 + low * 5)
1767
+ );
1738
1768
  return { name: "Memory", issues, score };
1739
1769
  }
1740
1770
 
@@ -2829,13 +2859,23 @@ function createEvalCommand() {
2829
2859
  let userChoseRuns = command.getOptionValueSource("runs") === "cli";
2830
2860
  const hasFlags = opts.suite || opts.model || opts.runs !== "3" || opts.timeout !== "120000" || opts.path !== process.cwd() || Boolean(opts.scenarios) || opts.json || opts.debug;
2831
2861
  if (!hasFlags) {
2862
+ const allScenarios = await loadScenarios({});
2863
+ const suiteCounts = /* @__PURE__ */ new Map();
2864
+ for (const s of allScenarios) {
2865
+ const suiteName = s.name.split("/")[0] ?? "misc";
2866
+ suiteCounts.set(suiteName, (suiteCounts.get(suiteName) ?? 0) + 1);
2867
+ }
2832
2868
  opts.suite = await select2({
2833
2869
  message: "Suite",
2834
2870
  choices: [
2835
- { name: "security (7 scenarios)", value: "security" },
2836
- { name: "conventions (5 scenarios)", value: "conventions" },
2837
- { name: "workflow (5 scenarios)", value: "workflow" },
2838
- { name: "all (17 scenarios)", value: void 0 }
2871
+ ...[...suiteCounts.entries()].map(([suiteName, count]) => ({
2872
+ name: `${suiteName} (${count} scenario${count === 1 ? "" : "s"})`,
2873
+ value: suiteName
2874
+ })),
2875
+ {
2876
+ name: `all (${allScenarios.length} scenarios)`,
2877
+ value: void 0
2878
+ }
2839
2879
  ]
2840
2880
  });
2841
2881
  opts.runs = await select2({
@@ -3096,9 +3136,9 @@ function createMemoryCommand() {
3096
3136
  );
3097
3137
  return;
3098
3138
  }
3099
- const { requireMemoryDeps } = await import("./require-deps-AEDO5YRM.js");
3139
+ const { requireMemoryDeps } = await import("./require-deps-GVBWF5PB.js");
3100
3140
  await requireMemoryDeps();
3101
- const { startTui } = await import("./tui-BS4XXLOC.js");
3141
+ const { startTui } = await import("./tui-ZINEA7TI.js");
3102
3142
  await startTui();
3103
3143
  return;
3104
3144
  }
@@ -3110,7 +3150,7 @@ function createMemoryCommand() {
3110
3150
  process.exitCode = 1;
3111
3151
  return;
3112
3152
  }
3113
- const { detectExistingSetup } = await import("./install-543ZKMXX.js");
3153
+ const { detectExistingSetup } = await import("./install-VREFJNLF.js");
3114
3154
  const existing = detectExistingSetup(process.cwd());
3115
3155
  const mcpMissing = existing !== null && !isMemoryMcpRegistered(process.cwd());
3116
3156
  if (existing) {
@@ -3147,12 +3187,12 @@ function createMemoryCommand() {
3147
3187
  log.info("Skipped.");
3148
3188
  return;
3149
3189
  }
3150
- const { runInstall } = await import("./install-543ZKMXX.js");
3190
+ const { runInstall } = await import("./install-VREFJNLF.js");
3151
3191
  await runInstall({});
3152
3192
  } else {
3153
- const { requireMemoryDeps } = await import("./require-deps-AEDO5YRM.js");
3193
+ const { requireMemoryDeps } = await import("./require-deps-GVBWF5PB.js");
3154
3194
  await requireMemoryDeps();
3155
- const { runStats } = await import("./stats-63L7C24W.js");
3195
+ const { runStats } = await import("./stats-TWIVFA4I.js");
3156
3196
  await runStats({});
3157
3197
  }
3158
3198
  });
@@ -3164,7 +3204,7 @@ function createMemoryCommand() {
3164
3204
  "Non-interactive: accept defaults (shared placement)"
3165
3205
  ).action(async (opts) => {
3166
3206
  try {
3167
- const { runInstall } = await import("./install-543ZKMXX.js");
3207
+ const { runInstall } = await import("./install-VREFJNLF.js");
3168
3208
  await runInstall({
3169
3209
  ...opts.dbPath ? { dbPath: opts.dbPath } : {},
3170
3210
  yes: opts.yes === true
@@ -3177,21 +3217,21 @@ function createMemoryCommand() {
3177
3217
  );
3178
3218
  memory.addCommand(
3179
3219
  new Command4("stats").description("Show memory counts, health, and injection stats").option("--json", "JSON output").action(async (opts) => {
3180
- const { requireMemoryDeps } = await import("./require-deps-AEDO5YRM.js");
3220
+ const { requireMemoryDeps } = await import("./require-deps-GVBWF5PB.js");
3181
3221
  await requireMemoryDeps();
3182
- const { runStats } = await import("./stats-63L7C24W.js");
3222
+ const { runStats } = await import("./stats-TWIVFA4I.js");
3183
3223
  await runStats(opts);
3184
3224
  })
3185
3225
  );
3186
3226
  memory.addCommand(
3187
3227
  new Command4("doctor").description("Diagnose the memory setup (DB, hooks, MCP registration)").option("--json", "JSON output").action(async (opts) => {
3188
- const { runMemoryDoctor } = await import("./doctor-EKGJ2YAO.js");
3228
+ const { runMemoryDoctor } = await import("./doctor-ESIQYNE4.js");
3189
3229
  await runMemoryDoctor(opts);
3190
3230
  })
3191
3231
  );
3192
3232
  memory.addCommand(
3193
3233
  new Command4("context").description("Load session context (hook handler)").option("--json", "JSON output").action(async (opts) => {
3194
- const { runContext } = await import("./context-3GHG7KW6.js");
3234
+ const { runContext } = await import("./context-K5B43NEI.js");
3195
3235
  await runContext(opts);
3196
3236
  }).helpCommand(false),
3197
3237
  { hidden: true }
@@ -3206,7 +3246,7 @@ function createMemoryCommand() {
3206
3246
  memory.addCommand(
3207
3247
  new Command4("push").description("Push current project's memories to GitHub Gist").option("--all", "Push all projects").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
3208
3248
  await handleSyncErrors(async () => {
3209
- const { runPush } = await import("./push-JXCWX4NY.js");
3249
+ const { runPush } = await import("./push-JDHT6AMD.js");
3210
3250
  await runPush(opts);
3211
3251
  });
3212
3252
  })
@@ -3217,7 +3257,7 @@ function createMemoryCommand() {
3217
3257
  "Non-interactive (accepted for symmetry with push; pull never prompts)"
3218
3258
  ).action(async (opts) => {
3219
3259
  await handleSyncErrors(async () => {
3220
- const { runPull } = await import("./pull-ULSZEVCR.js");
3260
+ const { runPull } = await import("./pull-H6ARY6DG.js");
3221
3261
  await runPull(opts);
3222
3262
  });
3223
3263
  })
@@ -3226,14 +3266,14 @@ function createMemoryCommand() {
3226
3266
  "Sync memories with the gist (pull + push); subcommands manage sync state"
3227
3267
  ).option("--all", "Sync all projects").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
3228
3268
  await handleSyncErrors(async () => {
3229
- const { runSync } = await import("./sync-QTJ6BXQ4.js");
3269
+ const { runSync } = await import("./sync-WG7OOWOX.js");
3230
3270
  await runSync(opts);
3231
3271
  });
3232
3272
  });
3233
3273
  sync.addCommand(
3234
3274
  new Command4("status").description("Show local vs remote memory counts per project").action(async () => {
3235
3275
  await handleSyncErrors(async () => {
3236
- const { runSyncStatus } = await import("./sync-status-EAX527SC.js");
3276
+ const { runSyncStatus } = await import("./sync-status-B3DKLET4.js");
3237
3277
  await runSyncStatus();
3238
3278
  });
3239
3279
  })
@@ -3241,7 +3281,7 @@ function createMemoryCommand() {
3241
3281
  sync.addCommand(
3242
3282
  new Command4("clean").description("Remove a project from the sync gist").argument("<project>", "Project slug to remove").option("-y, --yes", "Skip confirmation prompt").action(async (project, opts) => {
3243
3283
  await handleSyncErrors(async () => {
3244
- const { runSyncClean } = await import("./sync-clean-OJEK4XH4.js");
3284
+ const { runSyncClean } = await import("./sync-clean-GQUFTYG2.js");
3245
3285
  await runSyncClean(project, opts);
3246
3286
  });
3247
3287
  })
@@ -3251,7 +3291,7 @@ function createMemoryCommand() {
3251
3291
  }
3252
3292
 
3253
3293
  // src/cli.ts
3254
- var program = new Command5().name("claude-launchpad").description("Score your Claude Code config, fix the gaps, prove Claude follows your rules.").version("1.15.0", "-v, --version").action(async () => {
3294
+ var program = new Command5().name("claude-launchpad").description("Score your Claude Code config, fix the gaps, prove Claude follows your rules.").version("1.16.0", "-v, --version").action(async () => {
3255
3295
  const hasConfig = await fileExists(join14(process.cwd(), "CLAUDE.md")) || await fileExists(join14(process.cwd(), ".claude", "settings.json"));
3256
3296
  if (hasConfig) {
3257
3297
  await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });