claude-launchpad 1.12.0 → 1.14.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 (61) hide show
  1. package/README.md +11 -3
  2. package/dist/{chunk-DTCCQWOU.js → chunk-D6RAMWH6.js} +3 -3
  3. package/dist/{chunk-DTCCQWOU.js.map → chunk-D6RAMWH6.js.map} +1 -1
  4. package/dist/chunk-HSGSTSVN.js +212 -0
  5. package/dist/chunk-HSGSTSVN.js.map +1 -0
  6. package/dist/{chunk-DXDOVWOA.js → chunk-IDH3M4EI.js} +20 -232
  7. package/dist/chunk-IDH3M4EI.js.map +1 -0
  8. package/dist/{chunk-YZ53W47Z.js → chunk-IIWOSSL4.js} +2 -1
  9. package/dist/chunk-IIWOSSL4.js.map +1 -0
  10. package/dist/{chunk-ZLI4LI33.js → chunk-M6GVFN67.js} +2 -2
  11. package/dist/{chunk-F6SLV2FR.js → chunk-N2SCF7DB.js} +5 -6
  12. package/dist/chunk-N2SCF7DB.js.map +1 -0
  13. package/dist/chunk-OPORVSAF.js +225 -0
  14. package/dist/chunk-OPORVSAF.js.map +1 -0
  15. package/dist/{chunk-KPO4YURF.js → chunk-QEPE3WVF.js} +457 -85
  16. package/dist/chunk-QEPE3WVF.js.map +1 -0
  17. package/dist/chunk-UN43OVRW.js +184 -0
  18. package/dist/chunk-UN43OVRW.js.map +1 -0
  19. package/dist/{chunk-PH5OWJ42.js → chunk-VF7U63AI.js} +9 -5
  20. package/dist/{chunk-PH5OWJ42.js.map → chunk-VF7U63AI.js.map} +1 -1
  21. package/dist/cli.js +307 -87
  22. package/dist/cli.js.map +1 -1
  23. package/dist/commands/memory/server.js +48 -14
  24. package/dist/commands/memory/server.js.map +1 -1
  25. package/dist/{context-JALSYDYO.js → context-YIPO4LBS.js} +58 -55
  26. package/dist/context-YIPO4LBS.js.map +1 -0
  27. package/dist/doctor-DCHFJ3XV.js +108 -0
  28. package/dist/doctor-DCHFJ3XV.js.map +1 -0
  29. package/dist/{install-Q23F37GK.js → install-D32PV7SF.js} +12 -10
  30. package/dist/install-D32PV7SF.js.map +1 -0
  31. package/dist/{pull-FYKNNLYC.js → pull-YUQTDRUP.js} +17 -19
  32. package/dist/pull-YUQTDRUP.js.map +1 -0
  33. package/dist/{push-QSBK7BQU.js → push-U4IVTFOU.js} +13 -12
  34. package/dist/push-U4IVTFOU.js.map +1 -0
  35. package/dist/{require-deps-ZISUZLYD.js → require-deps-WDMHDGBN.js} +3 -3
  36. package/dist/{stats-SV53G6PQ.js → stats-77BYLKYP.js} +9 -7
  37. package/dist/{stats-SV53G6PQ.js.map → stats-77BYLKYP.js.map} +1 -1
  38. package/dist/{sync-2LDM44U4.js → sync-DTCWK2CY.js} +5 -5
  39. package/dist/{sync-clean-HQ523N7V.js → sync-clean-ACZCB3NZ.js} +4 -5
  40. package/dist/sync-clean-ACZCB3NZ.js.map +1 -0
  41. package/dist/{sync-status-V6WTI32X.js → sync-status-2V2RCYZO.js} +13 -12
  42. package/dist/sync-status-2V2RCYZO.js.map +1 -0
  43. package/dist/{tui-2UJ2OIHB.js → tui-HVJNLRY2.js} +11 -7
  44. package/dist/{tui-2UJ2OIHB.js.map → tui-HVJNLRY2.js.map} +1 -1
  45. package/package.json +27 -7
  46. package/scenarios/workflow/premature-victory.yaml +44 -0
  47. package/dist/chunk-DXDOVWOA.js.map +0 -1
  48. package/dist/chunk-F6SLV2FR.js.map +0 -1
  49. package/dist/chunk-KPO4YURF.js.map +0 -1
  50. package/dist/chunk-YZ53W47Z.js.map +0 -1
  51. package/dist/chunk-ZIG75MOB.js +0 -366
  52. package/dist/chunk-ZIG75MOB.js.map +0 -1
  53. package/dist/context-JALSYDYO.js.map +0 -1
  54. package/dist/install-Q23F37GK.js.map +0 -1
  55. package/dist/pull-FYKNNLYC.js.map +0 -1
  56. package/dist/push-QSBK7BQU.js.map +0 -1
  57. package/dist/sync-clean-HQ523N7V.js.map +0 -1
  58. package/dist/sync-status-V6WTI32X.js.map +0 -1
  59. /package/dist/{chunk-ZLI4LI33.js.map → chunk-M6GVFN67.js.map} +0 -0
  60. /package/dist/{require-deps-ZISUZLYD.js.map → require-deps-WDMHDGBN.js.map} +0 -0
  61. /package/dist/{sync-2LDM44U4.js.map → sync-DTCWK2CY.js.map} +0 -0
@@ -1372,6 +1372,43 @@ Output goes into the session's context. Always exit 0; SessionStart blocking is
1372
1372
  `;
1373
1373
  }
1374
1374
 
1375
+ // src/commands/init/generators/verification-rule.ts
1376
+ var VERIFICATION_RULE_VERSION = 1;
1377
+ function generateVerificationRule() {
1378
+ return `# Verification Rules
1379
+
1380
+ <!-- lp-verification-version: ${VERIFICATION_RULE_VERSION} -->
1381
+
1382
+ These rules govern every claim of "done", "fixed", "passing", or "works". A claim without evidence is a defect, no matter how good the code is.
1383
+
1384
+ ## Evidence before assertion
1385
+
1386
+ - Never claim done/fixed/passing without having run the thing this session and quoting the output. The claim and its evidence travel together: "Done \u2014 14/14 tests pass (output below)", never a bare "done".
1387
+ - Verify the behavior, not the build. Compiling is not working; typechecking is not working. Exercise the changed flow end-to-end: run the command, hit the endpoint, click the path.
1388
+ - For bug fixes: reproduce the failure FIRST and capture the exact error. Then fix, then re-run the original reproduction AND the surrounding tests. If you cannot explain the root cause, you have hidden the bug, not fixed it.
1389
+ - Test the failure case, not just the happy path: feed the change the input that used to break it and confirm it now lands safely.
1390
+
1391
+ ## Label your claims
1392
+
1393
+ Sort every load-bearing statement into one of three buckets, and say which out loud:
1394
+
1395
+ - **verified** \u2014 you read it or ran it this session
1396
+ - **inferred** \u2014 follows logically from verified facts; state the chain
1397
+ - **assumed** \u2014 plausible from prior knowledge; check it before building on it
1398
+
1399
+ Never let an assumption silently graduate into a fact. APIs, config keys, CLI flags, and package names cited from memory are the #1 hallucination vector \u2014 open the real source or current docs before citing them.
1400
+
1401
+ ## When you can't verify
1402
+
1403
+ - If a step cannot be run (missing env, no credentials, no test data), the result is **done-with-gaps** \u2014 name each gap explicitly. Never round done-with-gaps up to done.
1404
+ - Report failure plainly. Failing tests, skipped steps, and partial work get named with the output shown. "2 failures remain, here's the state" preserves trust; a false "all green" destroys it.
1405
+
1406
+ ## End-of-turn check
1407
+
1408
+ Before ending a turn, re-read your last paragraph. If it is a promise ("I'll\u2026", "next I would\u2026"), a plan, or a question you could answer yourself \u2014 do that work now, then end. A turn ends on delivered results, not intentions.
1409
+ `;
1410
+ }
1411
+
1375
1412
  // src/commands/init/generators/agent-reviewer.ts
1376
1413
  var REVIEWER_AGENT_VERSION = 1;
1377
1414
  function generateReviewerAgent() {
@@ -1425,7 +1462,9 @@ async function createWorkflowRule(root) {
1425
1462
  if (await fileExists(workflowPath)) return false;
1426
1463
  await mkdir2(rulesDir, { recursive: true });
1427
1464
  await writeFile3(workflowPath, generateWorkflowRule());
1428
- log.success("Created .claude/rules/workflow.md (path-scoped BACKLOG/TASKS workflow rules)");
1465
+ log.success(
1466
+ "Created .claude/rules/workflow.md (path-scoped BACKLOG/TASKS workflow rules)"
1467
+ );
1429
1468
  return true;
1430
1469
  }
1431
1470
  async function createReviewerAgent(root) {
@@ -1434,7 +1473,9 @@ async function createReviewerAgent(root) {
1434
1473
  if (await fileExists(agentPath)) return false;
1435
1474
  await mkdir2(agentsDir, { recursive: true });
1436
1475
  await writeFile3(agentPath, generateReviewerAgent());
1437
- log.success("Created .claude/agents/code-reviewer.md (fresh-context independent reviewer)");
1476
+ log.success(
1477
+ "Created .claude/agents/code-reviewer.md (fresh-context independent reviewer)"
1478
+ );
1438
1479
  return true;
1439
1480
  }
1440
1481
  async function updateWorkflowRule(root) {
@@ -1450,8 +1491,13 @@ async function fixStaleSwarmPhrase(root) {
1450
1491
  const claudeMdPath = join4(root, "CLAUDE.md");
1451
1492
  const content = await readFile3(claudeMdPath, "utf-8").catch(() => null);
1452
1493
  if (content === null || !content.includes(STALE_SWARM_PHRASE)) return false;
1453
- await writeFile3(claudeMdPath, content.replaceAll(STALE_SWARM_PHRASE, SWARM_PHRASE_REPLACEMENT));
1454
- log.success("Modernized Stop-and-Swarm wording (Agent tool \u2192 Task tool subagents)");
1494
+ await writeFile3(
1495
+ claudeMdPath,
1496
+ content.replaceAll(STALE_SWARM_PHRASE, SWARM_PHRASE_REPLACEMENT)
1497
+ );
1498
+ log.success(
1499
+ "Modernized Stop-and-Swarm wording (Agent tool \u2192 Task tool subagents)"
1500
+ );
1455
1501
  return true;
1456
1502
  }
1457
1503
  async function createHooksRule(root) {
@@ -1460,7 +1506,29 @@ async function createHooksRule(root) {
1460
1506
  if (await fileExists(hooksPath)) return false;
1461
1507
  await mkdir2(rulesDir, { recursive: true });
1462
1508
  await writeFile3(hooksPath, generateHooksRule());
1463
- log.success("Created .claude/rules/hooks.md (path-scoped hook authoring rules)");
1509
+ log.success(
1510
+ "Created .claude/rules/hooks.md (path-scoped hook authoring rules)"
1511
+ );
1512
+ return true;
1513
+ }
1514
+ async function createVerificationRule(root) {
1515
+ const rulesDir = join4(root, ".claude", "rules");
1516
+ const verificationPath = join4(rulesDir, "verification.md");
1517
+ if (await fileExists(verificationPath)) return false;
1518
+ await mkdir2(rulesDir, { recursive: true });
1519
+ await writeFile3(verificationPath, generateVerificationRule());
1520
+ log.success(
1521
+ "Created .claude/rules/verification.md (evidence-before-assertion discipline)"
1522
+ );
1523
+ return true;
1524
+ }
1525
+ async function updateVerificationRule(root) {
1526
+ const verificationPath = join4(root, ".claude", "rules", "verification.md");
1527
+ const content = await readFile3(verificationPath, "utf-8").catch(() => null);
1528
+ if (content === null) return false;
1529
+ if (!/<!-- lp-verification-version: \d+ -->/.test(content)) return false;
1530
+ await writeFile3(verificationPath, generateVerificationRule());
1531
+ log.success("Updated .claude/rules/verification.md to the latest version");
1464
1532
  return true;
1465
1533
  }
1466
1534
  function isMemoryHeading(line) {
@@ -1477,7 +1545,11 @@ function findMemoryBlocks(lines) {
1477
1545
  break;
1478
1546
  }
1479
1547
  }
1480
- blocks.push({ startIdx: i, endIdx: end, tagged: lines[i].includes("(agentic-memory)") });
1548
+ blocks.push({
1549
+ startIdx: i,
1550
+ endIdx: end,
1551
+ tagged: lines[i].includes("(agentic-memory)")
1552
+ });
1481
1553
  i = end - 1;
1482
1554
  }
1483
1555
  return blocks;
@@ -1512,7 +1584,9 @@ async function collapseMemoryHeadings(root) {
1512
1584
  (line) => /^## Memory\s*$/.test(line) ? "## Memory (agentic-memory)" : line
1513
1585
  );
1514
1586
  await writeFile3(claudeMdPath, canonical.join("\n"));
1515
- log.success(`Collapsed ${blocks.length - 1} duplicate ## Memory section(s) in CLAUDE.md`);
1587
+ log.success(
1588
+ `Collapsed ${blocks.length - 1} duplicate ## Memory section(s) in CLAUDE.md`
1589
+ );
1516
1590
  return true;
1517
1591
  }
1518
1592
 
@@ -1753,13 +1827,13 @@ async function addSessionStartPullHook(root, placement) {
1753
1827
  const target = placement === "local" ? "settings.local.json" : "settings.json";
1754
1828
  return addPlacementHook(root, placement, "SessionStart", "memory pull", {
1755
1829
  matcher: "startup",
1756
- hooks: [{ type: "command", command: "claude-launchpad memory pull -y 2>/dev/null; exit 0" }]
1830
+ hooks: [{ type: "command", command: "npx claude-launchpad memory pull -y 2>/dev/null; exit 0" }]
1757
1831
  }, true, `Added SessionStart hook for memory sync to ${target}`);
1758
1832
  }
1759
1833
  async function addSessionEndPushHook(root, placement) {
1760
1834
  const target = placement === "local" ? "settings.local.json" : "settings.json";
1761
1835
  return addPlacementHook(root, placement, "SessionEnd", "memory push", {
1762
- hooks: [{ type: "command", command: "nohup claude-launchpad memory push -y </dev/null >/dev/null 2>&1 & exit 0" }]
1836
+ hooks: [{ type: "command", command: "nohup npx claude-launchpad memory push -y </dev/null >/dev/null 2>&1 & exit 0" }]
1763
1837
  }, false, `Added SessionEnd hook for memory sync to ${target}`);
1764
1838
  }
1765
1839
  async function upgradeStaleSessionEndPushHook(root) {
@@ -1780,7 +1854,7 @@ async function upgradeStaleSessionEndPushHook(root) {
1780
1854
  const cmd = typeof h.command === "string" ? h.command : "";
1781
1855
  if (!cmd.includes("memory push") || cmd.includes("nohup")) return h;
1782
1856
  changed = true;
1783
- return { ...h, command: "nohup claude-launchpad memory push -y </dev/null >/dev/null 2>&1 & exit 0" };
1857
+ return { ...h, command: "nohup npx claude-launchpad memory push -y </dev/null >/dev/null 2>&1 & exit 0" };
1784
1858
  });
1785
1859
  return { ...group, hooks: rewritten };
1786
1860
  });
@@ -1868,6 +1942,38 @@ async function addAllowedMcpServers(root, placement) {
1868
1942
  log.success(`Added allowedMcpServers from configured servers to ${target}`);
1869
1943
  return true;
1870
1944
  }
1945
+ async function upgradeBareMemoryHooks(root) {
1946
+ let any = false;
1947
+ for (const placement of ["shared", "local"]) {
1948
+ const read = placement === "local" ? readSettingsLocalJson : readSettingsJson;
1949
+ const write = placement === "local" ? writeSettingsLocalJson : writeSettingsJson;
1950
+ const settings = await read(root);
1951
+ if (settings === null) continue;
1952
+ const hooks = settings.hooks;
1953
+ if (!hooks) continue;
1954
+ let changed = false;
1955
+ const upgradedHooks = {};
1956
+ for (const [event, groups] of Object.entries(hooks)) {
1957
+ upgradedHooks[event] = groups.map((group) => {
1958
+ const inner = group.hooks;
1959
+ if (!inner) return group;
1960
+ const rewritten = inner.map((h) => {
1961
+ const cmd = typeof h.command === "string" ? h.command : "";
1962
+ if (!cmd.includes("claude-launchpad memory") || cmd.includes("npx claude-launchpad")) return h;
1963
+ changed = true;
1964
+ return { ...h, command: cmd.replace("claude-launchpad memory", "npx claude-launchpad memory") };
1965
+ });
1966
+ return { ...group, hooks: rewritten };
1967
+ });
1968
+ }
1969
+ if (!changed) continue;
1970
+ await write(root, { ...settings, hooks: upgradedHooks });
1971
+ const target = placement === "local" ? "settings.local.json" : "settings.json";
1972
+ log.success(`Rewrote bare memory hook commands to npx form in ${target}`);
1973
+ any = true;
1974
+ }
1975
+ return any;
1976
+ }
1871
1977
 
1872
1978
  // src/commands/doctor/fixer.ts
1873
1979
  async function applyFixes(issues, projectRoot) {
@@ -1887,74 +1993,311 @@ async function applyFixes(issues, projectRoot) {
1887
1993
  return { fixed, skipped };
1888
1994
  }
1889
1995
  var FIX_TABLE = [
1890
- { analyzer: "Hooks", match: "$TOOL_INPUT_* env var", fix: (root) => rewriteEnvVarHooks(root) },
1891
- { analyzer: "Hooks", match: "No hooks configured", fix: async (root, detected) => {
1892
- const a = await addEnvProtectionHook(root);
1893
- const b = await addAutoFormatHook(root, detected);
1894
- const c = await addForcePushProtection(root);
1895
- const d = await addSessionStartHook(root);
1896
- return a || b || c || d;
1897
- } },
1898
- { analyzer: "Hooks", match: ".env file protection", fix: (root) => addEnvProtectionHook(root) },
1899
- { analyzer: "Hooks", match: "auto-format", fix: (root, detected) => addAutoFormatHook(root, detected) },
1900
- { analyzer: "Hooks", match: "No PreToolUse", fix: (root) => addEnvProtectionHook(root) },
1901
- { analyzer: "Quality", match: "Architecture", fix: (root) => addClaudeMdSection(root, "## Architecture", wrapStub("<!-- TODO: Describe your codebase structure. Run `/lp-enhance` to auto-fill this. -->")) },
1902
- { analyzer: "Quality", match: "Off-Limits", fix: (root) => addClaudeMdSection(root, "## Off-Limits", wrapStub(OFF_LIMITS_CONTENT)) },
1903
- { analyzer: "Quality", match: "Commands", fix: (root) => addClaudeMdSection(root, "## Commands", wrapStub("<!-- TODO: Add your dev/build/test commands -->")) },
1904
- { analyzer: "Quality", match: "Stack", fix: (root, detected) => {
1905
- if (detected.language) {
1906
- const content = `- **Language**: ${detected.language}${detected.framework ? `
1996
+ {
1997
+ analyzer: "Hooks",
1998
+ match: "$TOOL_INPUT_* env var",
1999
+ fix: (root) => rewriteEnvVarHooks(root)
2000
+ },
2001
+ {
2002
+ analyzer: "Hooks",
2003
+ match: "No hooks configured",
2004
+ fix: async (root, detected) => {
2005
+ const a = await addEnvProtectionHook(root);
2006
+ const b = await addAutoFormatHook(root, detected);
2007
+ const c = await addForcePushProtection(root);
2008
+ const d = await addSessionStartHook(root);
2009
+ return a || b || c || d;
2010
+ }
2011
+ },
2012
+ {
2013
+ analyzer: "Hooks",
2014
+ match: ".env file protection",
2015
+ fix: (root) => addEnvProtectionHook(root)
2016
+ },
2017
+ {
2018
+ analyzer: "Hooks",
2019
+ match: "auto-format",
2020
+ fix: (root, detected) => addAutoFormatHook(root, detected)
2021
+ },
2022
+ {
2023
+ analyzer: "Hooks",
2024
+ match: "No PreToolUse",
2025
+ fix: (root) => addEnvProtectionHook(root)
2026
+ },
2027
+ {
2028
+ analyzer: "Quality",
2029
+ match: "Architecture",
2030
+ fix: (root) => addClaudeMdSection(
2031
+ root,
2032
+ "## Architecture",
2033
+ wrapStub(
2034
+ "<!-- TODO: Describe your codebase structure. Run `/lp-enhance` to auto-fill this. -->"
2035
+ )
2036
+ )
2037
+ },
2038
+ {
2039
+ analyzer: "Quality",
2040
+ match: "Off-Limits",
2041
+ fix: (root) => addClaudeMdSection(root, "## Off-Limits", wrapStub(OFF_LIMITS_CONTENT))
2042
+ },
2043
+ {
2044
+ analyzer: "Quality",
2045
+ match: "Commands",
2046
+ fix: (root) => addClaudeMdSection(
2047
+ root,
2048
+ "## Commands",
2049
+ wrapStub("<!-- TODO: Add your dev/build/test commands -->")
2050
+ )
2051
+ },
2052
+ {
2053
+ analyzer: "Quality",
2054
+ match: "Stack",
2055
+ fix: (root, detected) => {
2056
+ if (detected.language) {
2057
+ const content = `- **Language**: ${detected.language}${detected.framework ? `
1907
2058
  - **Framework**: ${detected.framework}` : ""}${detected.packageManager ? `
1908
2059
  - **Package Manager**: ${detected.packageManager}` : ""}`;
1909
- return addClaudeMdSection(root, "## Stack", content);
2060
+ return addClaudeMdSection(root, "## Stack", content);
2061
+ }
2062
+ return addClaudeMdSection(
2063
+ root,
2064
+ "## Stack",
2065
+ wrapStub("<!-- TODO: Define your tech stack -->")
2066
+ );
1910
2067
  }
1911
- return addClaudeMdSection(root, "## Stack", wrapStub("<!-- TODO: Define your tech stack -->"));
1912
- } },
1913
- { analyzer: "Quality", match: "Session Start", fix: (root) => addClaudeMdSection(root, "## Session Start", wrapStub(SESSION_START_CONTENT)) },
1914
- { analyzer: "Quality", match: "Backlog", fix: (root) => addClaudeMdSection(root, "## Backlog", wrapStub(BACKLOG_CONTENT)) },
1915
- { analyzer: "Quality", match: "Stop-and-Swarm section is outdated", fix: (root) => fixStaleSwarmPhrase(root) },
1916
- { analyzer: "Quality", match: "Stop-and-Swarm", fix: (root) => addClaudeMdSection(root, "## Stop-and-Swarm", wrapStub(STOP_AND_SWARM_CONTENT)) },
1917
- { analyzer: "Rules", match: "workflow.md rule is outdated", fix: (root) => updateWorkflowRule(root) },
1918
- { analyzer: "Rules", match: "No .claude/agents/code-reviewer.md", fix: (root) => createReviewerAgent(root) },
1919
- { analyzer: "Quality", match: "Duplicate ## Memory", fix: (root) => collapseMemoryHeadings(root) },
1920
- { analyzer: "Rules", match: "No BACKLOG.md", fix: (root) => createBacklogMd(root) },
1921
- { analyzer: "Rules", match: "No .claudeignore", fix: (root, detected) => createClaudeignore(root, detected) },
1922
- { analyzer: "Rules", match: "No .claude/rules/workflow.md", fix: (root) => createWorkflowRule(root) },
1923
- { analyzer: "Rules", match: "No .claude/rules/hooks.md", fix: (root) => createHooksRule(root) },
1924
- { analyzer: "Rules", match: "No .claude/rules/", fix: (root) => createStarterRules(root) },
1925
- { analyzer: "Hooks", match: "PostCompact hooks can't inject context", fix: (root) => migratePostCompactHook(root) },
1926
- { analyzer: "Hooks", match: "compact matcher", fix: (root) => addCompactMatcherHook(root) },
1927
- { analyzer: "Permissions", match: "force-push", fix: (root) => addForcePushProtection(root) },
1928
- { analyzer: "Permissions", match: "Credential files not blocked", fix: (root) => addCredentialDenyRules(root) },
1929
- { analyzer: "Permissions", match: "Bypass permissions mode", fix: (root) => addBypassDisable(root) },
1930
- { analyzer: "Permissions", match: "Sandbox lacks a write grant", fix: (root) => addSandboxMemoryWriteGrant(root) },
1931
- { analyzer: "Permissions", match: ".env is protected by hooks but not in .claudeignore", fix: (root) => addEnvToClaudeignore(root) },
1932
- { analyzer: "Permissions", match: ".worktreeinclude is missing or empty", fix: (root) => createWorktreeInclude(root) },
1933
- { analyzer: "Hooks", match: "registered on PreToolUse", fix: (root) => migrateSprintOpenHookEvent(root) },
1934
- { analyzer: "Hooks", match: "nudge uses bare stdout", fix: (root) => upgradeStaleNudge(root) },
1935
- { analyzer: "Hooks", match: "Outdated hygiene script", fix: (root) => refreshHygieneScripts(root) },
1936
- { analyzer: "Hooks", match: "sprint-size-check", fix: (root) => addSprintSizeHook(root) },
1937
- { analyzer: "Hooks", match: "sprint-open-check", fix: (root) => addSprintOpenHook(root) },
1938
- { analyzer: "Hooks", match: "sprint-complete nudge", fix: (root) => addSprintCompleteNudge(root) },
1939
- { analyzer: "Hooks", match: "workflow-check.sh", fix: (root) => addWorkflowCheckHook(root) },
1940
- { analyzer: "Rules", match: "No skill authoring conventions", fix: (root) => addSkillAuthoringConventions(root) },
1941
- { analyzer: "Rules", match: "No /lp-enhance skill", fix: (root) => createEnhanceSkill(root) },
1942
- { analyzer: "Rules", match: "lp-enhance skill is outdated", fix: (root) => updateEnhanceSkill(root) },
1943
- { analyzer: "Settings", match: "Deprecated includeCoAuthoredBy", fix: (root) => migrateAttribution(root) },
1944
- { analyzer: "Hooks", match: "SessionStart", fix: (root) => addSessionStartHook(root) },
1945
- { analyzer: "Memory", match: "Deprecated Stop hook", fix: (root) => removeStaleStopHook(root) },
1946
- { analyzer: "Memory", match: "autoMemoryEnabled not disabled", fix: (root, _det, placement) => disableAutoMemory(root, placement) },
1947
- { analyzer: "Memory", match: "MCP tool permission", fix: (root, _det, placement) => addMemoryToolPermissions(root, placement) },
1948
- { analyzer: "MCP", match: "no allowedMcpServers", fix: (root, _det, placement) => addAllowedMcpServers(root, placement) },
1949
- { analyzer: "Memory", match: "allowedMcpServers is set but does not include agentic-memory", fix: (root) => addMemoryToAllowedMcpServers(root) },
1950
- { analyzer: "Memory", match: "SessionStart hook to auto-pull", fix: (root, _det, placement) => addSessionStartPullHook(root, placement) },
1951
- { analyzer: "Memory", match: "SessionEnd hook to auto-push", fix: (root, _det, placement) => addSessionEndPushHook(root, placement) },
1952
- { analyzer: "Memory", match: "SessionEnd push hook is not nohup-wrapped", fix: (root) => upgradeStaleSessionEndPushHook(root) },
1953
- { analyzer: "Memory", match: "CLAUDE.md missing memory guidance", fix: (root, _det, placement) => {
1954
- const content = "Use agentic-memory to persist knowledge across sessions:\n- Memories are automatically injected at session start\n- STORE IMMEDIATELY when: a dependency strategy changes, an architecture decision is made, a convention is established, a bug pattern is discovered, or a feature is killed/added\n- Use memory_search before memory_store to check for duplicates\n- NEVER store credentials, API keys, tokens, or secrets in memories";
1955
- const target = placement === "local" ? join7(root, ".claude", "CLAUDE.md") : void 0;
1956
- return addClaudeMdSection(root, "## Memory", wrapStub(content), target);
1957
- } }
2068
+ },
2069
+ {
2070
+ analyzer: "Quality",
2071
+ match: "Session Start",
2072
+ fix: (root) => addClaudeMdSection(
2073
+ root,
2074
+ "## Session Start",
2075
+ wrapStub(SESSION_START_CONTENT)
2076
+ )
2077
+ },
2078
+ {
2079
+ analyzer: "Quality",
2080
+ match: "Backlog",
2081
+ fix: (root) => addClaudeMdSection(root, "## Backlog", wrapStub(BACKLOG_CONTENT))
2082
+ },
2083
+ {
2084
+ analyzer: "Quality",
2085
+ match: "Stop-and-Swarm section is outdated",
2086
+ fix: (root) => fixStaleSwarmPhrase(root)
2087
+ },
2088
+ {
2089
+ analyzer: "Quality",
2090
+ match: "Stop-and-Swarm",
2091
+ fix: (root) => addClaudeMdSection(
2092
+ root,
2093
+ "## Stop-and-Swarm",
2094
+ wrapStub(STOP_AND_SWARM_CONTENT)
2095
+ )
2096
+ },
2097
+ {
2098
+ analyzer: "Rules",
2099
+ match: "workflow.md rule is outdated",
2100
+ fix: (root) => updateWorkflowRule(root)
2101
+ },
2102
+ {
2103
+ analyzer: "Rules",
2104
+ match: "verification.md rule is outdated",
2105
+ fix: (root) => updateVerificationRule(root)
2106
+ },
2107
+ {
2108
+ analyzer: "Rules",
2109
+ match: "No .claude/agents/code-reviewer.md",
2110
+ fix: (root) => createReviewerAgent(root)
2111
+ },
2112
+ {
2113
+ analyzer: "Quality",
2114
+ match: "Duplicate ## Memory",
2115
+ fix: (root) => collapseMemoryHeadings(root)
2116
+ },
2117
+ {
2118
+ analyzer: "Rules",
2119
+ match: "No BACKLOG.md",
2120
+ fix: (root) => createBacklogMd(root)
2121
+ },
2122
+ {
2123
+ analyzer: "Rules",
2124
+ match: "No .claudeignore",
2125
+ fix: (root, detected) => createClaudeignore(root, detected)
2126
+ },
2127
+ {
2128
+ analyzer: "Rules",
2129
+ match: "No .claude/rules/workflow.md",
2130
+ fix: (root) => createWorkflowRule(root)
2131
+ },
2132
+ {
2133
+ analyzer: "Rules",
2134
+ match: "No .claude/rules/hooks.md",
2135
+ fix: (root) => createHooksRule(root)
2136
+ },
2137
+ {
2138
+ analyzer: "Rules",
2139
+ match: "No .claude/rules/verification.md",
2140
+ fix: (root) => createVerificationRule(root)
2141
+ },
2142
+ {
2143
+ analyzer: "Rules",
2144
+ match: "No .claude/rules/",
2145
+ fix: (root) => createStarterRules(root)
2146
+ },
2147
+ {
2148
+ analyzer: "Hooks",
2149
+ match: "PostCompact hooks can't inject context",
2150
+ fix: (root) => migratePostCompactHook(root)
2151
+ },
2152
+ {
2153
+ analyzer: "Hooks",
2154
+ match: "compact matcher",
2155
+ fix: (root) => addCompactMatcherHook(root)
2156
+ },
2157
+ {
2158
+ analyzer: "Permissions",
2159
+ match: "force-push",
2160
+ fix: (root) => addForcePushProtection(root)
2161
+ },
2162
+ {
2163
+ analyzer: "Permissions",
2164
+ match: "Credential files not blocked",
2165
+ fix: (root) => addCredentialDenyRules(root)
2166
+ },
2167
+ {
2168
+ analyzer: "Permissions",
2169
+ match: "Bypass permissions mode",
2170
+ fix: (root) => addBypassDisable(root)
2171
+ },
2172
+ {
2173
+ analyzer: "Permissions",
2174
+ match: "Sandbox lacks a write grant",
2175
+ fix: (root) => addSandboxMemoryWriteGrant(root)
2176
+ },
2177
+ {
2178
+ analyzer: "Permissions",
2179
+ match: ".env is protected by hooks but not in .claudeignore",
2180
+ fix: (root) => addEnvToClaudeignore(root)
2181
+ },
2182
+ {
2183
+ analyzer: "Permissions",
2184
+ match: ".worktreeinclude is missing or empty",
2185
+ fix: (root) => createWorktreeInclude(root)
2186
+ },
2187
+ {
2188
+ analyzer: "Hooks",
2189
+ match: "registered on PreToolUse",
2190
+ fix: (root) => migrateSprintOpenHookEvent(root)
2191
+ },
2192
+ {
2193
+ analyzer: "Hooks",
2194
+ match: "nudge uses bare stdout",
2195
+ fix: (root) => upgradeStaleNudge(root)
2196
+ },
2197
+ {
2198
+ analyzer: "Hooks",
2199
+ match: "Outdated hygiene script",
2200
+ fix: (root) => refreshHygieneScripts(root)
2201
+ },
2202
+ {
2203
+ analyzer: "Hooks",
2204
+ match: "sprint-size-check",
2205
+ fix: (root) => addSprintSizeHook(root)
2206
+ },
2207
+ {
2208
+ analyzer: "Hooks",
2209
+ match: "sprint-open-check",
2210
+ fix: (root) => addSprintOpenHook(root)
2211
+ },
2212
+ {
2213
+ analyzer: "Hooks",
2214
+ match: "sprint-complete nudge",
2215
+ fix: (root) => addSprintCompleteNudge(root)
2216
+ },
2217
+ {
2218
+ analyzer: "Hooks",
2219
+ match: "workflow-check.sh",
2220
+ fix: (root) => addWorkflowCheckHook(root)
2221
+ },
2222
+ {
2223
+ analyzer: "Rules",
2224
+ match: "No skill authoring conventions",
2225
+ fix: (root) => addSkillAuthoringConventions(root)
2226
+ },
2227
+ {
2228
+ analyzer: "Rules",
2229
+ match: "No /lp-enhance skill",
2230
+ fix: (root) => createEnhanceSkill(root)
2231
+ },
2232
+ {
2233
+ analyzer: "Rules",
2234
+ match: "lp-enhance skill is outdated",
2235
+ fix: (root) => updateEnhanceSkill(root)
2236
+ },
2237
+ {
2238
+ analyzer: "Settings",
2239
+ match: "Deprecated includeCoAuthoredBy",
2240
+ fix: (root) => migrateAttribution(root)
2241
+ },
2242
+ {
2243
+ analyzer: "Hooks",
2244
+ match: "SessionStart",
2245
+ fix: (root) => addSessionStartHook(root)
2246
+ },
2247
+ {
2248
+ analyzer: "Memory",
2249
+ match: "bare claude-launchpad binary",
2250
+ fix: (root) => upgradeBareMemoryHooks(root)
2251
+ },
2252
+ {
2253
+ analyzer: "Memory",
2254
+ match: "Deprecated Stop hook",
2255
+ fix: (root) => removeStaleStopHook(root)
2256
+ },
2257
+ {
2258
+ analyzer: "Memory",
2259
+ match: "autoMemoryEnabled not disabled",
2260
+ fix: (root, _det, placement) => disableAutoMemory(root, placement)
2261
+ },
2262
+ {
2263
+ analyzer: "Memory",
2264
+ match: "MCP tool permission",
2265
+ fix: (root, _det, placement) => addMemoryToolPermissions(root, placement)
2266
+ },
2267
+ {
2268
+ analyzer: "MCP",
2269
+ match: "no allowedMcpServers",
2270
+ fix: (root, _det, placement) => addAllowedMcpServers(root, placement)
2271
+ },
2272
+ {
2273
+ analyzer: "Memory",
2274
+ match: "allowedMcpServers is set but does not include agentic-memory",
2275
+ fix: (root) => addMemoryToAllowedMcpServers(root)
2276
+ },
2277
+ {
2278
+ analyzer: "Memory",
2279
+ match: "SessionStart hook to auto-pull",
2280
+ fix: (root, _det, placement) => addSessionStartPullHook(root, placement)
2281
+ },
2282
+ {
2283
+ analyzer: "Memory",
2284
+ match: "SessionEnd hook to auto-push",
2285
+ fix: (root, _det, placement) => addSessionEndPushHook(root, placement)
2286
+ },
2287
+ {
2288
+ analyzer: "Memory",
2289
+ match: "SessionEnd push hook is not nohup-wrapped",
2290
+ fix: (root) => upgradeStaleSessionEndPushHook(root)
2291
+ },
2292
+ {
2293
+ analyzer: "Memory",
2294
+ match: "CLAUDE.md missing memory guidance",
2295
+ fix: (root, _det, placement) => {
2296
+ const content = "Use agentic-memory to persist knowledge across sessions:\n- Memories are automatically injected at session start\n- STORE IMMEDIATELY when: a dependency strategy changes, an architecture decision is made, a convention is established, a bug pattern is discovered, or a feature is killed/added\n- Use memory_search before memory_store to check for duplicates\n- NEVER store credentials, API keys, tokens, or secrets in memories";
2297
+ const target = placement === "local" ? join7(root, ".claude", "CLAUDE.md") : void 0;
2298
+ return addClaudeMdSection(root, "## Memory", wrapStub(content), target);
2299
+ }
2300
+ }
1958
2301
  ];
1959
2302
  function hasAutoFix(issue) {
1960
2303
  return FIX_TABLE.some(
@@ -1985,7 +2328,10 @@ async function addCredentialDenyRules(root) {
1985
2328
  const toAdd = ["Read(~/.ssh/*)", "Read(~/.aws/*)", "Read(~/.npmrc)"];
1986
2329
  const missing = toAdd.filter((p) => !deny.includes(p));
1987
2330
  if (missing.length === 0) return false;
1988
- const updated = { ...settings, permissions: { ...permissions, deny: [...deny, ...missing] } };
2331
+ const updated = {
2332
+ ...settings,
2333
+ permissions: { ...permissions, deny: [...deny, ...missing] }
2334
+ };
1989
2335
  await writeSettingsJson(root, updated);
1990
2336
  log.success("Added credential deny rules (SSH, AWS, npm)");
1991
2337
  return true;
@@ -2011,11 +2357,16 @@ async function addSandboxMemoryWriteGrant(root) {
2011
2357
  ...settings,
2012
2358
  sandbox: {
2013
2359
  ...sandbox,
2014
- filesystem: { ...filesystem, allowWrite: [...allowWrite, "~/.agentic-memory"] }
2360
+ filesystem: {
2361
+ ...filesystem,
2362
+ allowWrite: [...allowWrite, "~/.agentic-memory"]
2363
+ }
2015
2364
  }
2016
2365
  };
2017
2366
  await writeSettingsJson(root, updated);
2018
- log.success("Added ~/.agentic-memory to sandbox.filesystem.allowWrite (sandbox stays enabled)");
2367
+ log.success(
2368
+ "Added ~/.agentic-memory to sandbox.filesystem.allowWrite (sandbox stays enabled)"
2369
+ );
2019
2370
  return true;
2020
2371
  }
2021
2372
  async function addEnvToClaudeignore(root) {
@@ -2027,7 +2378,8 @@ async function addEnvToClaudeignore(root) {
2027
2378
  return false;
2028
2379
  }
2029
2380
  const lines = content.split("\n").map((l) => l.trim());
2030
- if (lines.some((l) => l === ".env" || l === ".env.*" || l === ".env*")) return false;
2381
+ if (lines.some((l) => l === ".env" || l === ".env.*" || l === ".env*"))
2382
+ return false;
2031
2383
  await writeFile4(ignorePath, content.trimEnd() + "\n.env\n.env.*\n");
2032
2384
  log.success("Added .env to .claudeignore");
2033
2385
  return true;
@@ -2061,7 +2413,9 @@ async function createBacklogMd(root) {
2061
2413
  if (await fileExists(backlogPath)) return false;
2062
2414
  const name = root.split("/").pop() ?? "Project";
2063
2415
  await writeFile4(backlogPath, generateBacklogMd({ name, description: "" }));
2064
- log.success("Generated BACKLOG.md (WP template + P0\u2013P3 sections + changelog)");
2416
+ log.success(
2417
+ "Generated BACKLOG.md (WP template + P0\u2013P3 sections + changelog)"
2418
+ );
2065
2419
  return true;
2066
2420
  }
2067
2421
  async function createClaudeignore(root, detected) {
@@ -2103,17 +2457,27 @@ async function addSkillAuthoringConventions(root) {
2103
2457
  return false;
2104
2458
  }
2105
2459
  if (/^##\s+Skill\s+Authoring/im.test(content)) return false;
2106
- await writeFile4(conventionsPath, content.trimEnd() + "\n" + SKILL_AUTHORING_SECTION);
2460
+ await writeFile4(
2461
+ conventionsPath,
2462
+ content.trimEnd() + "\n" + SKILL_AUTHORING_SECTION
2463
+ );
2107
2464
  log.success("Added Skill Authoring section to .claude/rules/conventions.md");
2108
2465
  return true;
2109
2466
  }
2110
2467
  async function createEnhanceSkill(root) {
2111
2468
  const skillDir = join7(root, ".claude", "skills", "lp-enhance");
2112
2469
  const skillPath = join7(skillDir, "SKILL.md");
2113
- const globalPath = join7(homedir(), ".claude", "skills", "lp-enhance", "SKILL.md");
2470
+ const globalPath = join7(
2471
+ homedir(),
2472
+ ".claude",
2473
+ "skills",
2474
+ "lp-enhance",
2475
+ "SKILL.md"
2476
+ );
2114
2477
  const legacyProject = join7(root, ".claude", "commands", "lp-enhance.md");
2115
2478
  const legacyGlobal = join7(homedir(), ".claude", "commands", "lp-enhance.md");
2116
- if (await fileExists(skillPath) || await fileExists(globalPath) || await fileExists(legacyProject) || await fileExists(legacyGlobal)) return false;
2479
+ if (await fileExists(skillPath) || await fileExists(globalPath) || await fileExists(legacyProject) || await fileExists(legacyGlobal))
2480
+ return false;
2117
2481
  await mkdir3(skillDir, { recursive: true });
2118
2482
  await writeFile4(skillPath, generateEnhanceSkill());
2119
2483
  log.success("Generated /lp-enhance skill (.claude/skills/lp-enhance/)");
@@ -2121,7 +2485,13 @@ async function createEnhanceSkill(root) {
2121
2485
  }
2122
2486
  async function updateEnhanceSkill(root) {
2123
2487
  const projectPath = join7(root, ".claude", "skills", "lp-enhance", "SKILL.md");
2124
- const globalPath = join7(homedir(), ".claude", "skills", "lp-enhance", "SKILL.md");
2488
+ const globalPath = join7(
2489
+ homedir(),
2490
+ ".claude",
2491
+ "skills",
2492
+ "lp-enhance",
2493
+ "SKILL.md"
2494
+ );
2125
2495
  const targetPath = await fileExists(projectPath) ? projectPath : await fileExists(globalPath) ? globalPath : null;
2126
2496
  if (!targetPath) return false;
2127
2497
  await writeFile4(targetPath, generateEnhanceSkill());
@@ -2303,6 +2673,8 @@ export {
2303
2673
  WORKFLOW_RULE_VERSION,
2304
2674
  generateWorkflowRule,
2305
2675
  generateHooksRule,
2676
+ VERIFICATION_RULE_VERSION,
2677
+ generateVerificationRule,
2306
2678
  generateReviewerAgent,
2307
2679
  applyFixes,
2308
2680
  log,
@@ -2310,4 +2682,4 @@ export {
2310
2682
  printScoreCard,
2311
2683
  renderDoctorReport
2312
2684
  };
2313
- //# sourceMappingURL=chunk-KPO4YURF.js.map
2685
+ //# sourceMappingURL=chunk-QEPE3WVF.js.map