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.
- package/README.md +11 -3
- package/dist/{chunk-DTCCQWOU.js → chunk-D6RAMWH6.js} +3 -3
- package/dist/{chunk-DTCCQWOU.js.map → chunk-D6RAMWH6.js.map} +1 -1
- package/dist/chunk-HSGSTSVN.js +212 -0
- package/dist/chunk-HSGSTSVN.js.map +1 -0
- package/dist/{chunk-DXDOVWOA.js → chunk-IDH3M4EI.js} +20 -232
- package/dist/chunk-IDH3M4EI.js.map +1 -0
- package/dist/{chunk-YZ53W47Z.js → chunk-IIWOSSL4.js} +2 -1
- package/dist/chunk-IIWOSSL4.js.map +1 -0
- package/dist/{chunk-ZLI4LI33.js → chunk-M6GVFN67.js} +2 -2
- package/dist/{chunk-F6SLV2FR.js → chunk-N2SCF7DB.js} +5 -6
- package/dist/chunk-N2SCF7DB.js.map +1 -0
- package/dist/chunk-OPORVSAF.js +225 -0
- package/dist/chunk-OPORVSAF.js.map +1 -0
- package/dist/{chunk-KPO4YURF.js → chunk-QEPE3WVF.js} +457 -85
- package/dist/chunk-QEPE3WVF.js.map +1 -0
- package/dist/chunk-UN43OVRW.js +184 -0
- package/dist/chunk-UN43OVRW.js.map +1 -0
- package/dist/{chunk-PH5OWJ42.js → chunk-VF7U63AI.js} +9 -5
- package/dist/{chunk-PH5OWJ42.js.map → chunk-VF7U63AI.js.map} +1 -1
- package/dist/cli.js +307 -87
- package/dist/cli.js.map +1 -1
- package/dist/commands/memory/server.js +48 -14
- package/dist/commands/memory/server.js.map +1 -1
- package/dist/{context-JALSYDYO.js → context-YIPO4LBS.js} +58 -55
- package/dist/context-YIPO4LBS.js.map +1 -0
- package/dist/doctor-DCHFJ3XV.js +108 -0
- package/dist/doctor-DCHFJ3XV.js.map +1 -0
- package/dist/{install-Q23F37GK.js → install-D32PV7SF.js} +12 -10
- package/dist/install-D32PV7SF.js.map +1 -0
- package/dist/{pull-FYKNNLYC.js → pull-YUQTDRUP.js} +17 -19
- package/dist/pull-YUQTDRUP.js.map +1 -0
- package/dist/{push-QSBK7BQU.js → push-U4IVTFOU.js} +13 -12
- package/dist/push-U4IVTFOU.js.map +1 -0
- package/dist/{require-deps-ZISUZLYD.js → require-deps-WDMHDGBN.js} +3 -3
- package/dist/{stats-SV53G6PQ.js → stats-77BYLKYP.js} +9 -7
- package/dist/{stats-SV53G6PQ.js.map → stats-77BYLKYP.js.map} +1 -1
- package/dist/{sync-2LDM44U4.js → sync-DTCWK2CY.js} +5 -5
- package/dist/{sync-clean-HQ523N7V.js → sync-clean-ACZCB3NZ.js} +4 -5
- package/dist/sync-clean-ACZCB3NZ.js.map +1 -0
- package/dist/{sync-status-V6WTI32X.js → sync-status-2V2RCYZO.js} +13 -12
- package/dist/sync-status-2V2RCYZO.js.map +1 -0
- package/dist/{tui-2UJ2OIHB.js → tui-HVJNLRY2.js} +11 -7
- package/dist/{tui-2UJ2OIHB.js.map → tui-HVJNLRY2.js.map} +1 -1
- package/package.json +27 -7
- package/scenarios/workflow/premature-victory.yaml +44 -0
- package/dist/chunk-DXDOVWOA.js.map +0 -1
- package/dist/chunk-F6SLV2FR.js.map +0 -1
- package/dist/chunk-KPO4YURF.js.map +0 -1
- package/dist/chunk-YZ53W47Z.js.map +0 -1
- package/dist/chunk-ZIG75MOB.js +0 -366
- package/dist/chunk-ZIG75MOB.js.map +0 -1
- package/dist/context-JALSYDYO.js.map +0 -1
- package/dist/install-Q23F37GK.js.map +0 -1
- package/dist/pull-FYKNNLYC.js.map +0 -1
- package/dist/push-QSBK7BQU.js.map +0 -1
- package/dist/sync-clean-HQ523N7V.js.map +0 -1
- package/dist/sync-status-V6WTI32X.js.map +0 -1
- /package/dist/{chunk-ZLI4LI33.js.map → chunk-M6GVFN67.js.map} +0 -0
- /package/dist/{require-deps-ZISUZLYD.js.map → require-deps-WDMHDGBN.js.map} +0 -0
- /package/dist/{sync-2LDM44U4.js.map → sync-DTCWK2CY.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
readSyncConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-M6GVFN67.js";
|
|
5
5
|
import {
|
|
6
6
|
BACKLOG_CONTENT,
|
|
7
7
|
ENHANCE_SKILL_VERSION,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
STALE_SWARM_PHRASE,
|
|
17
17
|
STOP_AND_SWARM_CONTENT,
|
|
18
18
|
TESTING_DISCIPLINE_CONTENT,
|
|
19
|
+
VERIFICATION_RULE_VERSION,
|
|
19
20
|
WORKFLOW_CHECK_WRAPPER,
|
|
20
21
|
WORKFLOW_RULE_VERSION,
|
|
21
22
|
applyFixes,
|
|
@@ -26,6 +27,7 @@ import {
|
|
|
26
27
|
generateEnhanceSkill,
|
|
27
28
|
generateHooksRule,
|
|
28
29
|
generateReviewerAgent,
|
|
30
|
+
generateVerificationRule,
|
|
29
31
|
generateWorkflowRule,
|
|
30
32
|
hasEnvVarHookPattern,
|
|
31
33
|
isJqAvailable,
|
|
@@ -38,7 +40,7 @@ import {
|
|
|
38
40
|
sprintReviewsContent,
|
|
39
41
|
writeSprintHygieneScripts,
|
|
40
42
|
writeWorkflowCheckScript
|
|
41
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-QEPE3WVF.js";
|
|
42
44
|
|
|
43
45
|
// src/cli.ts
|
|
44
46
|
import { Command as Command5 } from "commander";
|
|
@@ -250,16 +252,22 @@ function dirTreeContains(dir, needle, depth) {
|
|
|
250
252
|
|
|
251
253
|
// src/commands/init/index.ts
|
|
252
254
|
function createInitCommand() {
|
|
253
|
-
return new Command("init").description("Set up Claude Code configuration for any project").option("-n, --name <name>", "Project name").option(
|
|
255
|
+
return new Command("init").description("Set up Claude Code configuration for any project").option("-n, --name <name>", "Project name").option(
|
|
256
|
+
"-y, --yes",
|
|
257
|
+
"Accept all defaults (does not overwrite existing files)"
|
|
258
|
+
).option("-f, --force", "Overwrite existing CLAUDE.md").action(async (opts) => {
|
|
254
259
|
printBanner();
|
|
255
260
|
const root = process.cwd();
|
|
256
261
|
log.step("Detecting project...");
|
|
257
262
|
const detected = await detectProject(root);
|
|
258
263
|
if (detected.language) {
|
|
259
264
|
log.success(`Found ${detected.framework ?? detected.language} project`);
|
|
260
|
-
if (detected.packageManager)
|
|
261
|
-
|
|
262
|
-
if (detected.
|
|
265
|
+
if (detected.packageManager)
|
|
266
|
+
log.info(`Package manager: ${detected.packageManager}`);
|
|
267
|
+
if (detected.devCommand)
|
|
268
|
+
log.info(`Dev command: ${detected.devCommand}`);
|
|
269
|
+
if (detected.testCommand)
|
|
270
|
+
log.info(`Test command: ${detected.testCommand}`);
|
|
263
271
|
} else {
|
|
264
272
|
log.warn("Could not detect project type \u2014 generating minimal config");
|
|
265
273
|
}
|
|
@@ -271,13 +279,18 @@ function createInitCommand() {
|
|
|
271
279
|
const description = opts.yes ? "" : await input({
|
|
272
280
|
message: "One-line description (optional):"
|
|
273
281
|
});
|
|
274
|
-
const options = {
|
|
282
|
+
const options = {
|
|
283
|
+
name: name.trim(),
|
|
284
|
+
description: description.trim()
|
|
285
|
+
};
|
|
275
286
|
const hasClaudeMd = await fileExists(join2(root, "CLAUDE.md"));
|
|
276
287
|
if (hasClaudeMd) {
|
|
277
288
|
if (opts.force) {
|
|
278
289
|
log.warn("Overwriting existing CLAUDE.md (--force)");
|
|
279
290
|
} else if (opts.yes) {
|
|
280
|
-
log.error(
|
|
291
|
+
log.error(
|
|
292
|
+
"CLAUDE.md already exists. `--yes` will not overwrite existing files."
|
|
293
|
+
);
|
|
281
294
|
log.info("Run `claude-launchpad doctor --fix` to update in place,");
|
|
282
295
|
log.info("or re-run with `--force` to overwrite.");
|
|
283
296
|
process.exitCode = 1;
|
|
@@ -290,7 +303,9 @@ function createInitCommand() {
|
|
|
290
303
|
if (!overwrite) {
|
|
291
304
|
log.info("Keeping existing CLAUDE.md");
|
|
292
305
|
await createEnhanceSkillPrompt(root, false);
|
|
293
|
-
log.step(
|
|
306
|
+
log.step(
|
|
307
|
+
"Tip: run `claude-launchpad doctor` to check your existing config"
|
|
308
|
+
);
|
|
294
309
|
return;
|
|
295
310
|
}
|
|
296
311
|
}
|
|
@@ -300,14 +315,19 @@ function createInitCommand() {
|
|
|
300
315
|
}
|
|
301
316
|
async function scaffold(root, options, detected, skipPrompts) {
|
|
302
317
|
log.step("Generating configuration...");
|
|
303
|
-
const claudeMd = generateClaudeMd(options, detected, {
|
|
318
|
+
const claudeMd = generateClaudeMd(options, detected, {
|
|
319
|
+
superpowers: isSuperpowersInstalled()
|
|
320
|
+
});
|
|
304
321
|
const tasksMd = generateTasksMd(options);
|
|
305
322
|
const backlogMd = generateBacklogMd(options);
|
|
306
323
|
const settings = generateSettings(detected);
|
|
307
324
|
const claudeignore = generateClaudeignore(detected);
|
|
308
325
|
await mkdir(join2(root, ".claude", "rules"), { recursive: true });
|
|
309
326
|
const settingsPath = join2(root, ".claude", "settings.json");
|
|
310
|
-
const mergedSettings = await mergeSettings(
|
|
327
|
+
const mergedSettings = await mergeSettings(
|
|
328
|
+
settingsPath,
|
|
329
|
+
settings
|
|
330
|
+
);
|
|
311
331
|
const backlogPath = join2(root, "BACKLOG.md");
|
|
312
332
|
const hasBacklog = await fileExists(backlogPath);
|
|
313
333
|
const claudeignorePath = join2(root, ".claudeignore");
|
|
@@ -320,6 +340,13 @@ async function scaffold(root, options, detected, skipPrompts) {
|
|
|
320
340
|
const hasWorkflowRule = await fileExists(workflowRulePath);
|
|
321
341
|
const hooksRulePath = join2(root, ".claude", "rules", "hooks.md");
|
|
322
342
|
const hasHooksRule = await fileExists(hooksRulePath);
|
|
343
|
+
const verificationRulePath = join2(
|
|
344
|
+
root,
|
|
345
|
+
".claude",
|
|
346
|
+
"rules",
|
|
347
|
+
"verification.md"
|
|
348
|
+
);
|
|
349
|
+
const hasVerificationRule = await fileExists(verificationRulePath);
|
|
323
350
|
const writes = [
|
|
324
351
|
writeFile(join2(root, "CLAUDE.md"), claudeMd),
|
|
325
352
|
writeFile(join2(root, "TASKS.md"), tasksMd),
|
|
@@ -332,16 +359,21 @@ async function scaffold(root, options, detected, skipPrompts) {
|
|
|
332
359
|
writes.push(writeFile(claudeignorePath, claudeignore));
|
|
333
360
|
}
|
|
334
361
|
if (!hasClaudeGitignore) {
|
|
335
|
-
writes.push(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
362
|
+
writes.push(
|
|
363
|
+
writeFile(
|
|
364
|
+
claudeGitignorePath,
|
|
365
|
+
[
|
|
366
|
+
"# Local-only Claude Code files (never commit these)",
|
|
367
|
+
"CLAUDE.md",
|
|
368
|
+
"settings.local.json",
|
|
369
|
+
"plans/",
|
|
370
|
+
"memory/",
|
|
371
|
+
"sessions/",
|
|
372
|
+
"tmp/",
|
|
373
|
+
""
|
|
374
|
+
].join("\n")
|
|
375
|
+
)
|
|
376
|
+
);
|
|
345
377
|
}
|
|
346
378
|
if (!hasRules) {
|
|
347
379
|
const rulesContent = generateStarterRules(detected);
|
|
@@ -353,6 +385,9 @@ async function scaffold(root, options, detected, skipPrompts) {
|
|
|
353
385
|
if (!hasHooksRule) {
|
|
354
386
|
writes.push(writeFile(hooksRulePath, generateHooksRule()));
|
|
355
387
|
}
|
|
388
|
+
if (!hasVerificationRule) {
|
|
389
|
+
writes.push(writeFile(verificationRulePath, generateVerificationRule()));
|
|
390
|
+
}
|
|
356
391
|
const reviewerAgentPath = join2(root, ".claude", "agents", "code-reviewer.md");
|
|
357
392
|
const hasReviewerAgent = await fileExists(reviewerAgentPath);
|
|
358
393
|
if (!hasReviewerAgent) {
|
|
@@ -363,26 +398,47 @@ async function scaffold(root, options, detected, skipPrompts) {
|
|
|
363
398
|
await writeSprintHygieneScripts(root);
|
|
364
399
|
await writeWorkflowCheckScript(root);
|
|
365
400
|
log.success("Generated CLAUDE.md");
|
|
366
|
-
if (!hasReviewerAgent)
|
|
401
|
+
if (!hasReviewerAgent)
|
|
402
|
+
log.success(
|
|
403
|
+
"Generated .claude/agents/code-reviewer.md (independent sprint reviewer)"
|
|
404
|
+
);
|
|
367
405
|
log.success("Generated TASKS.md");
|
|
368
406
|
if (!hasBacklog) log.success("Generated BACKLOG.md");
|
|
369
407
|
log.success("Generated .claude/settings.json (schema, permissions, hooks)");
|
|
370
408
|
if (!hasClaudeGitignore) log.success("Generated .claude/.gitignore");
|
|
371
409
|
if (!hasClaudeignore) log.success("Generated .claudeignore");
|
|
372
410
|
if (!hasRules) log.success("Generated .claude/rules/conventions.md");
|
|
373
|
-
if (!hasWorkflowRule)
|
|
374
|
-
|
|
375
|
-
|
|
411
|
+
if (!hasWorkflowRule)
|
|
412
|
+
log.success(
|
|
413
|
+
"Generated .claude/rules/workflow.md (workflow rules, path-scoped)"
|
|
414
|
+
);
|
|
415
|
+
if (!hasHooksRule)
|
|
416
|
+
log.success(
|
|
417
|
+
"Generated .claude/rules/hooks.md (hook authoring rules, path-scoped)"
|
|
418
|
+
);
|
|
419
|
+
if (!hasVerificationRule)
|
|
420
|
+
log.success(
|
|
421
|
+
"Generated .claude/rules/verification.md (evidence-before-assertion discipline)"
|
|
422
|
+
);
|
|
423
|
+
log.success(
|
|
424
|
+
"Generated .claude/hooks/sprint-{size,open}-check.sh + workflow-check.sh"
|
|
425
|
+
);
|
|
376
426
|
await createEnhanceSkillPrompt(root, skipPrompts);
|
|
377
427
|
log.blank();
|
|
378
428
|
if (!isJqAvailable()) {
|
|
379
|
-
log.warn(
|
|
429
|
+
log.warn(
|
|
430
|
+
"jq not found on PATH \u2014 the generated hooks (including the .env and destructive-command guards) will silently no-op until you install it: https://jqlang.github.io/jq/download/"
|
|
431
|
+
);
|
|
380
432
|
}
|
|
381
433
|
if (!isSuperpowersInstalled()) {
|
|
382
|
-
log.info(
|
|
434
|
+
log.info(
|
|
435
|
+
"Optional: the superpowers plugin adds brainstorm/plan/TDD/review discipline \u2014 /plugin install superpowers@claude-plugins-official"
|
|
436
|
+
);
|
|
383
437
|
}
|
|
384
438
|
log.success("Done! Run `claude` to start.");
|
|
385
|
-
log.info(
|
|
439
|
+
log.info(
|
|
440
|
+
"Use `/lp-enhance` inside Claude Code to have AI complete your CLAUDE.md."
|
|
441
|
+
);
|
|
386
442
|
log.info("Run `claude-launchpad doctor` to check your config quality.");
|
|
387
443
|
log.blank();
|
|
388
444
|
}
|
|
@@ -414,19 +470,32 @@ function generateStarterRules(detected) {
|
|
|
414
470
|
lines.push("", "## Testing Discipline", "", TESTING_DISCIPLINE_CONTENT);
|
|
415
471
|
const verify = [detected.testCommand, detected.lintCommand].filter((c) => !!c).map((c) => `\`${c}\``).join(" && ");
|
|
416
472
|
lines.push("", "## Pre-Commit Checklist", "");
|
|
417
|
-
lines.push(
|
|
418
|
-
|
|
419
|
-
|
|
473
|
+
lines.push(
|
|
474
|
+
verify ? `1. Run ${verify} \u2014 never commit if either fails` : "1. Run the project's test and typecheck commands \u2014 never commit if either fails"
|
|
475
|
+
);
|
|
476
|
+
lines.push(
|
|
477
|
+
"2. For hard-TDD surfaces, confirm the test was written before the implementation"
|
|
478
|
+
);
|
|
479
|
+
lines.push(
|
|
480
|
+
"3. Before sprint-ending commits: run /code-review on the sprint diff (see ## Sprint Reviews in CLAUDE.md)"
|
|
481
|
+
);
|
|
420
482
|
lines.push("", "## Skill Authoring", "", SKILL_AUTHORING_CONTENT);
|
|
421
483
|
lines.push("");
|
|
422
484
|
return lines.join("\n");
|
|
423
485
|
}
|
|
424
486
|
async function createEnhanceSkillPrompt(root, skipPrompts) {
|
|
425
487
|
const projectPath = join2(root, ".claude", "skills", "lp-enhance", "SKILL.md");
|
|
426
|
-
const globalPath = join2(
|
|
488
|
+
const globalPath = join2(
|
|
489
|
+
homedir2(),
|
|
490
|
+
".claude",
|
|
491
|
+
"skills",
|
|
492
|
+
"lp-enhance",
|
|
493
|
+
"SKILL.md"
|
|
494
|
+
);
|
|
427
495
|
const legacyProject = join2(root, ".claude", "commands", "lp-enhance.md");
|
|
428
496
|
const legacyGlobal = join2(homedir2(), ".claude", "commands", "lp-enhance.md");
|
|
429
|
-
if (await fileExists(projectPath) || await fileExists(globalPath) || await fileExists(legacyProject) || await fileExists(legacyGlobal))
|
|
497
|
+
if (await fileExists(projectPath) || await fileExists(globalPath) || await fileExists(legacyProject) || await fileExists(legacyGlobal))
|
|
498
|
+
return;
|
|
430
499
|
const scope = skipPrompts ? "project" : await select({
|
|
431
500
|
message: "Install /lp-enhance skill (AI-powered CLAUDE.md improver):",
|
|
432
501
|
choices: [
|
|
@@ -443,7 +512,9 @@ async function createEnhanceSkillPrompt(root, skipPrompts) {
|
|
|
443
512
|
}
|
|
444
513
|
async function mergeSettings(existingPath, generated) {
|
|
445
514
|
try {
|
|
446
|
-
const existing = JSON.parse(
|
|
515
|
+
const existing = JSON.parse(
|
|
516
|
+
await readFile(existingPath, "utf-8")
|
|
517
|
+
);
|
|
447
518
|
const existingHooks = existing.hooks ?? {};
|
|
448
519
|
const generatedHooks = generated.hooks ?? {};
|
|
449
520
|
const mergedHooks = { ...existingHooks };
|
|
@@ -1000,7 +1071,9 @@ async function analyzeRules(config) {
|
|
|
1000
1071
|
fix: "Run `claude-launchpad init` or `doctor --fix` to generate one"
|
|
1001
1072
|
});
|
|
1002
1073
|
}
|
|
1003
|
-
const hasWorkflowRule = await fileExists(
|
|
1074
|
+
const hasWorkflowRule = await fileExists(
|
|
1075
|
+
join4(projectRoot, ".claude", "rules", "workflow.md")
|
|
1076
|
+
);
|
|
1004
1077
|
if (!hasWorkflowRule) {
|
|
1005
1078
|
issues.push({
|
|
1006
1079
|
analyzer: "Rules",
|
|
@@ -1009,7 +1082,9 @@ async function analyzeRules(config) {
|
|
|
1009
1082
|
fix: "Run `doctor --fix` to generate it"
|
|
1010
1083
|
});
|
|
1011
1084
|
}
|
|
1012
|
-
const hasReviewerAgent = await fileExists(
|
|
1085
|
+
const hasReviewerAgent = await fileExists(
|
|
1086
|
+
join4(projectRoot, ".claude", "agents", "code-reviewer.md")
|
|
1087
|
+
);
|
|
1013
1088
|
if (!hasReviewerAgent) {
|
|
1014
1089
|
issues.push({
|
|
1015
1090
|
analyzer: "Rules",
|
|
@@ -1026,7 +1101,10 @@ async function analyzeRules(config) {
|
|
|
1026
1101
|
});
|
|
1027
1102
|
}
|
|
1028
1103
|
if (hasWorkflowRule) {
|
|
1029
|
-
const wfContent = await readFile2(
|
|
1104
|
+
const wfContent = await readFile2(
|
|
1105
|
+
join4(projectRoot, ".claude", "rules", "workflow.md"),
|
|
1106
|
+
"utf-8"
|
|
1107
|
+
).catch(() => "");
|
|
1030
1108
|
const wfMatch = wfContent.match(/<!-- lp-workflow-version: (\d+) -->/);
|
|
1031
1109
|
const wfVersion = wfMatch ? parseInt(wfMatch[1], 10) : null;
|
|
1032
1110
|
if (wfVersion !== null && wfVersion < WORKFLOW_RULE_VERSION) {
|
|
@@ -1038,7 +1116,9 @@ async function analyzeRules(config) {
|
|
|
1038
1116
|
});
|
|
1039
1117
|
}
|
|
1040
1118
|
}
|
|
1041
|
-
const hasHooksRule = await fileExists(
|
|
1119
|
+
const hasHooksRule = await fileExists(
|
|
1120
|
+
join4(projectRoot, ".claude", "rules", "hooks.md")
|
|
1121
|
+
);
|
|
1042
1122
|
if (!hasHooksRule) {
|
|
1043
1123
|
issues.push({
|
|
1044
1124
|
analyzer: "Rules",
|
|
@@ -1047,6 +1127,33 @@ async function analyzeRules(config) {
|
|
|
1047
1127
|
fix: "Run `doctor --fix` to generate it"
|
|
1048
1128
|
});
|
|
1049
1129
|
}
|
|
1130
|
+
const verificationPath = join4(
|
|
1131
|
+
projectRoot,
|
|
1132
|
+
".claude",
|
|
1133
|
+
"rules",
|
|
1134
|
+
"verification.md"
|
|
1135
|
+
);
|
|
1136
|
+
const hasVerificationRule = await fileExists(verificationPath);
|
|
1137
|
+
if (!hasVerificationRule) {
|
|
1138
|
+
issues.push({
|
|
1139
|
+
analyzer: "Rules",
|
|
1140
|
+
severity: "medium",
|
|
1141
|
+
message: "No .claude/rules/verification.md found \u2014 nothing stops premature 'done' claims without evidence",
|
|
1142
|
+
fix: "Run `doctor --fix` to generate it"
|
|
1143
|
+
});
|
|
1144
|
+
} else {
|
|
1145
|
+
const vContent = await readFile2(verificationPath, "utf-8").catch(() => "");
|
|
1146
|
+
const vMatch = vContent.match(/<!-- lp-verification-version: (\d+) -->/);
|
|
1147
|
+
const vVersion = vMatch ? parseInt(vMatch[1], 10) : null;
|
|
1148
|
+
if (vVersion !== null && vVersion < VERIFICATION_RULE_VERSION) {
|
|
1149
|
+
issues.push({
|
|
1150
|
+
analyzer: "Rules",
|
|
1151
|
+
severity: "low",
|
|
1152
|
+
message: `verification.md rule is outdated (v${vVersion}, latest v${VERIFICATION_RULE_VERSION})`,
|
|
1153
|
+
fix: "Run `doctor --fix` to update it"
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1050
1157
|
const hasClaudeignore = await fileExists(join4(projectRoot, ".claudeignore"));
|
|
1051
1158
|
if (!hasClaudeignore) {
|
|
1052
1159
|
issues.push({
|
|
@@ -1059,7 +1166,9 @@ async function analyzeRules(config) {
|
|
|
1059
1166
|
const hasSkillInProject = config.skills.some(
|
|
1060
1167
|
(s) => basename(s) === "SKILL.md" && s.includes("lp-enhance") || basename(s) === "lp-enhance.md"
|
|
1061
1168
|
);
|
|
1062
|
-
const hasSkillGlobal = await fileExists(
|
|
1169
|
+
const hasSkillGlobal = await fileExists(
|
|
1170
|
+
join4(homedir3(), ".claude", "skills", "lp-enhance", "SKILL.md")
|
|
1171
|
+
) || await fileExists(join4(homedir3(), ".claude", "commands", "lp-enhance.md"));
|
|
1063
1172
|
if (!hasSkillInProject && !hasSkillGlobal) {
|
|
1064
1173
|
issues.push({
|
|
1065
1174
|
analyzer: "Rules",
|
|
@@ -1530,6 +1639,17 @@ async function analyzeMemory(config, projectRoot) {
|
|
|
1530
1639
|
fix: "Run `doctor --fix` to add agentic-memory to allowedMcpServers"
|
|
1531
1640
|
});
|
|
1532
1641
|
}
|
|
1642
|
+
const hasBareBinaryHook = config.hooks.some(
|
|
1643
|
+
(h) => h.command?.includes("claude-launchpad memory") && !h.command.includes("npx claude-launchpad")
|
|
1644
|
+
);
|
|
1645
|
+
if (hasBareBinaryHook) {
|
|
1646
|
+
issues.push({
|
|
1647
|
+
analyzer: "Memory",
|
|
1648
|
+
severity: "medium",
|
|
1649
|
+
message: "Memory hook(s) call the bare claude-launchpad binary \u2014 fails silently on machines without a global install",
|
|
1650
|
+
fix: "Run `doctor --fix` to rewrite them to the npx form"
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1533
1653
|
const syncConfig = readSyncConfig();
|
|
1534
1654
|
if (syncConfig) {
|
|
1535
1655
|
const hasSessionStartPull = config.hooks.some(
|
|
@@ -2305,6 +2425,10 @@ async function listYamlFiles(dir) {
|
|
|
2305
2425
|
return [];
|
|
2306
2426
|
}
|
|
2307
2427
|
}
|
|
2428
|
+
function resolveRuns(scenarioRuns, cliRuns, userChoseRuns) {
|
|
2429
|
+
if (userChoseRuns) return cliRuns;
|
|
2430
|
+
return scenarioRuns ?? cliRuns;
|
|
2431
|
+
}
|
|
2308
2432
|
|
|
2309
2433
|
// src/commands/eval/runner.ts
|
|
2310
2434
|
import { mkdir as mkdir2, writeFile as writeFile2, rm, cp } from "fs/promises";
|
|
@@ -2616,8 +2740,19 @@ async function scoreResults(scenario, sandboxDir, transcript, model) {
|
|
|
2616
2740
|
|
|
2617
2741
|
// src/commands/eval/index.ts
|
|
2618
2742
|
function createEvalCommand() {
|
|
2619
|
-
return new Command3("eval").description("Test your Claude Code config against eval scenarios").option(
|
|
2743
|
+
return new Command3("eval").description("Test your Claude Code config against eval scenarios").option(
|
|
2744
|
+
"-s, --suite <suite>",
|
|
2745
|
+
"Eval suite to run (e.g., security, conventions, workflow)"
|
|
2746
|
+
).option("-p, --path <path>", "Project root path", process.cwd()).option("--scenarios <path>", "Custom scenarios directory").option("--runs <n>", "Runs per scenario (default: 3)", "3").option(
|
|
2747
|
+
"--timeout <ms>",
|
|
2748
|
+
"Timeout per run in ms (default: 120000)",
|
|
2749
|
+
"120000"
|
|
2750
|
+
).option("--json", "Output as JSON").option("--debug", "Keep sandbox directories for inspection").option(
|
|
2751
|
+
"--model <model>",
|
|
2752
|
+
"Model to use for eval (e.g., sonnet, haiku, opus)"
|
|
2753
|
+
).action(async (opts, command) => {
|
|
2620
2754
|
printBanner();
|
|
2755
|
+
let userChoseRuns = command.getOptionValueSource("runs") === "cli";
|
|
2621
2756
|
const hasFlags = opts.suite || opts.model || opts.runs !== "3" || opts.timeout !== "120000" || opts.path !== process.cwd() || Boolean(opts.scenarios) || opts.json || opts.debug;
|
|
2622
2757
|
if (!hasFlags) {
|
|
2623
2758
|
opts.suite = await select2({
|
|
@@ -2625,8 +2760,8 @@ function createEvalCommand() {
|
|
|
2625
2760
|
choices: [
|
|
2626
2761
|
{ name: "security (7 scenarios)", value: "security" },
|
|
2627
2762
|
{ name: "conventions (5 scenarios)", value: "conventions" },
|
|
2628
|
-
{ name: "workflow (
|
|
2629
|
-
{ name: "all (
|
|
2763
|
+
{ name: "workflow (5 scenarios)", value: "workflow" },
|
|
2764
|
+
{ name: "all (17 scenarios)", value: void 0 }
|
|
2630
2765
|
]
|
|
2631
2766
|
});
|
|
2632
2767
|
opts.runs = await select2({
|
|
@@ -2637,6 +2772,7 @@ function createEvalCommand() {
|
|
|
2637
2772
|
{ name: "5 \u2014 thorough", value: "5" }
|
|
2638
2773
|
]
|
|
2639
2774
|
});
|
|
2775
|
+
userChoseRuns = true;
|
|
2640
2776
|
opts.model = await select2({
|
|
2641
2777
|
message: "Model",
|
|
2642
2778
|
choices: [
|
|
@@ -2649,8 +2785,12 @@ function createEvalCommand() {
|
|
|
2649
2785
|
}
|
|
2650
2786
|
const claudeAvailable = await checkClaudeCli();
|
|
2651
2787
|
if (!claudeAvailable) {
|
|
2652
|
-
log.error(
|
|
2653
|
-
|
|
2788
|
+
log.error(
|
|
2789
|
+
"Claude CLI not found. Install it: https://docs.anthropic.com/en/docs/claude-code"
|
|
2790
|
+
);
|
|
2791
|
+
log.info(
|
|
2792
|
+
"The eval command runs Claude headless against scenarios \u2014 it requires the CLI."
|
|
2793
|
+
);
|
|
2654
2794
|
process.exit(1);
|
|
2655
2795
|
}
|
|
2656
2796
|
log.step("Loading eval scenarios...");
|
|
@@ -2661,7 +2801,9 @@ function createEvalCommand() {
|
|
|
2661
2801
|
if (scenarios.length === 0) {
|
|
2662
2802
|
log.warn("No matching scenarios found.");
|
|
2663
2803
|
if (opts.suite) {
|
|
2664
|
-
log.info(
|
|
2804
|
+
log.info(
|
|
2805
|
+
`Check that the suite "${opts.suite}" exists in the scenarios directory.`
|
|
2806
|
+
);
|
|
2665
2807
|
}
|
|
2666
2808
|
return;
|
|
2667
2809
|
}
|
|
@@ -2670,10 +2812,11 @@ function createEvalCommand() {
|
|
|
2670
2812
|
log.info(`Model: ${opts.model}`);
|
|
2671
2813
|
}
|
|
2672
2814
|
log.blank();
|
|
2673
|
-
const
|
|
2815
|
+
const cliRuns = parseInt(opts.runs, 10);
|
|
2674
2816
|
const timeout = parseInt(opts.timeout, 10);
|
|
2675
2817
|
const results = [];
|
|
2676
2818
|
for (const scenario of scenarios) {
|
|
2819
|
+
const runs = resolveRuns(scenario.runs, cliRuns, userChoseRuns);
|
|
2677
2820
|
const spinner = ora({
|
|
2678
2821
|
text: `Running: ${scenario.name} (${runs} run${runs > 1 ? "s" : ""})`,
|
|
2679
2822
|
prefixText: " "
|
|
@@ -2681,13 +2824,22 @@ function createEvalCommand() {
|
|
|
2681
2824
|
try {
|
|
2682
2825
|
const result = await runScenarioWithRetries(
|
|
2683
2826
|
{ ...scenario, runs },
|
|
2684
|
-
{
|
|
2827
|
+
{
|
|
2828
|
+
projectRoot: opts.path,
|
|
2829
|
+
timeout,
|
|
2830
|
+
debug: opts.debug,
|
|
2831
|
+
model: opts.model
|
|
2832
|
+
}
|
|
2685
2833
|
);
|
|
2686
2834
|
results.push(result);
|
|
2687
2835
|
if (result.passed) {
|
|
2688
|
-
spinner.succeed(
|
|
2836
|
+
spinner.succeed(
|
|
2837
|
+
`${scenario.name} ${result.score}/${result.maxScore}`
|
|
2838
|
+
);
|
|
2689
2839
|
} else {
|
|
2690
|
-
spinner.fail(
|
|
2840
|
+
spinner.fail(
|
|
2841
|
+
`${scenario.name} ${result.score}/${result.maxScore}`
|
|
2842
|
+
);
|
|
2691
2843
|
}
|
|
2692
2844
|
} catch (error) {
|
|
2693
2845
|
spinner.fail(`${scenario.name} ERROR`);
|
|
@@ -2698,7 +2850,11 @@ function createEvalCommand() {
|
|
|
2698
2850
|
score: 0,
|
|
2699
2851
|
maxScore: scenario.checks.reduce((s, c) => s + c.points, 0),
|
|
2700
2852
|
passed: false,
|
|
2701
|
-
checks: scenario.checks.map((c) => ({
|
|
2853
|
+
checks: scenario.checks.map((c) => ({
|
|
2854
|
+
label: c.label,
|
|
2855
|
+
passed: false,
|
|
2856
|
+
points: c.points
|
|
2857
|
+
}))
|
|
2702
2858
|
});
|
|
2703
2859
|
}
|
|
2704
2860
|
}
|
|
@@ -2706,13 +2862,19 @@ function createEvalCommand() {
|
|
|
2706
2862
|
if (opts.json) {
|
|
2707
2863
|
const overallScore = results.reduce((s, r) => s + r.score, 0);
|
|
2708
2864
|
const overallMax = results.reduce((s, r) => s + r.maxScore, 0);
|
|
2709
|
-
console.log(
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2865
|
+
console.log(
|
|
2866
|
+
JSON.stringify(
|
|
2867
|
+
{
|
|
2868
|
+
results,
|
|
2869
|
+
overallScore,
|
|
2870
|
+
overallMax,
|
|
2871
|
+
passed: overallScore >= overallMax * 0.8,
|
|
2872
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2873
|
+
},
|
|
2874
|
+
null,
|
|
2875
|
+
2
|
|
2876
|
+
)
|
|
2877
|
+
);
|
|
2716
2878
|
return;
|
|
2717
2879
|
}
|
|
2718
2880
|
renderEvalReport(results);
|
|
@@ -2724,7 +2886,9 @@ function renderEvalReport(results) {
|
|
|
2724
2886
|
const icon = result.passed ? chalk2.green("\u2713") : chalk2.red("\u2717");
|
|
2725
2887
|
const status = result.passed ? chalk2.green("PASS") : chalk2.red("FAIL");
|
|
2726
2888
|
const score = `${result.score}/${result.maxScore}`;
|
|
2727
|
-
console.log(
|
|
2889
|
+
console.log(
|
|
2890
|
+
` ${icon} ${chalk2.bold(result.scenario)} ${score} ${status}`
|
|
2891
|
+
);
|
|
2728
2892
|
const failedChecks = result.checks.filter((c) => !c.passed);
|
|
2729
2893
|
for (const check of failedChecks) {
|
|
2730
2894
|
console.log(` ${chalk2.red("\u2717")} ${chalk2.dim(check.label)}`);
|
|
@@ -2741,7 +2905,9 @@ function renderEvalReport(results) {
|
|
|
2741
2905
|
if (failed === 0) {
|
|
2742
2906
|
log.success(`All ${passed} scenario(s) passed.`);
|
|
2743
2907
|
} else {
|
|
2744
|
-
log.warn(
|
|
2908
|
+
log.warn(
|
|
2909
|
+
`${passed} passed, ${failed} failed out of ${results.length} scenario(s).`
|
|
2910
|
+
);
|
|
2745
2911
|
}
|
|
2746
2912
|
}
|
|
2747
2913
|
async function saveEvalReport(results, projectRoot, suite, model) {
|
|
@@ -2765,7 +2931,9 @@ async function saveEvalReport(results, projectRoot, suite, model) {
|
|
|
2765
2931
|
];
|
|
2766
2932
|
for (const result of results) {
|
|
2767
2933
|
const status = result.passed ? "PASS" : "FAIL";
|
|
2768
|
-
lines.push(
|
|
2934
|
+
lines.push(
|
|
2935
|
+
`### ${result.scenario} \u2014 ${result.score}/${result.maxScore} ${status}`
|
|
2936
|
+
);
|
|
2769
2937
|
const failedChecks = result.checks.filter((c) => !c.passed);
|
|
2770
2938
|
const passedChecks = result.checks.filter((c) => c.passed);
|
|
2771
2939
|
for (const check of passedChecks) {
|
|
@@ -2783,7 +2951,9 @@ async function saveEvalReport(results, projectRoot, suite, model) {
|
|
|
2783
2951
|
lines.push(`### Fix: ${result.scenario}`);
|
|
2784
2952
|
const failedChecks = result.checks.filter((c) => !c.passed);
|
|
2785
2953
|
for (const check of failedChecks) {
|
|
2786
|
-
lines.push(
|
|
2954
|
+
lines.push(
|
|
2955
|
+
`- ${check.label} \u2014 update CLAUDE.md instructions or add hooks to enforce this behavior`
|
|
2956
|
+
);
|
|
2787
2957
|
}
|
|
2788
2958
|
lines.push("");
|
|
2789
2959
|
}
|
|
@@ -2833,43 +3003,66 @@ function hasMemoryHook(path) {
|
|
|
2833
3003
|
const sessionStart = hooks.SessionStart;
|
|
2834
3004
|
return sessionStart?.some((h) => {
|
|
2835
3005
|
const inner = h.hooks;
|
|
2836
|
-
return inner?.some(
|
|
3006
|
+
return inner?.some(
|
|
3007
|
+
(ih) => String(ih.command ?? "").includes("memory context")
|
|
3008
|
+
);
|
|
2837
3009
|
}) ?? false;
|
|
2838
3010
|
} catch {
|
|
2839
3011
|
return false;
|
|
2840
3012
|
}
|
|
2841
3013
|
}
|
|
2842
3014
|
function createMemoryCommand() {
|
|
2843
|
-
const memory = new Command4("memory").description("Project-scoped memory with decay, sync, and a TUI dashboard").
|
|
3015
|
+
const memory = new Command4("memory").description("Project-scoped memory with decay, sync, and a TUI dashboard").showHelpAfterError(
|
|
3016
|
+
"(see `claude-launchpad memory --help` for the available subcommands)"
|
|
3017
|
+
).showSuggestionAfterError(true).option("--dashboard", "Open the memory dashboard").action(async (opts) => {
|
|
2844
3018
|
if (opts.dashboard) {
|
|
2845
3019
|
if (!isMemoryInstalled()) {
|
|
2846
|
-
log.error(
|
|
3020
|
+
log.error(
|
|
3021
|
+
"Knowledge base not set up yet. Run `claude-launchpad memory` first."
|
|
3022
|
+
);
|
|
2847
3023
|
return;
|
|
2848
3024
|
}
|
|
2849
|
-
const { requireMemoryDeps } = await import("./require-deps-
|
|
3025
|
+
const { requireMemoryDeps } = await import("./require-deps-WDMHDGBN.js");
|
|
2850
3026
|
await requireMemoryDeps();
|
|
2851
|
-
const { startTui } = await import("./tui-
|
|
3027
|
+
const { startTui } = await import("./tui-HVJNLRY2.js");
|
|
2852
3028
|
await startTui();
|
|
2853
3029
|
return;
|
|
2854
3030
|
}
|
|
2855
3031
|
if (!isMemoryInstalled()) {
|
|
2856
|
-
|
|
3032
|
+
if (!process.stdin.isTTY) {
|
|
3033
|
+
log.error(
|
|
3034
|
+
"Knowledge base not set up and no TTY to prompt. Run `claude-launchpad memory install -y`."
|
|
3035
|
+
);
|
|
3036
|
+
process.exitCode = 1;
|
|
3037
|
+
return;
|
|
3038
|
+
}
|
|
3039
|
+
const { detectExistingSetup } = await import("./install-D32PV7SF.js");
|
|
2857
3040
|
const existing = detectExistingSetup(process.cwd());
|
|
2858
3041
|
const mcpMissing = existing !== null && !isMemoryMcpRegistered(process.cwd());
|
|
2859
3042
|
if (existing) {
|
|
2860
3043
|
const location = existing === "local" ? ".claude/CLAUDE.md + settings.local.json" : "CLAUDE.md + settings.json";
|
|
2861
3044
|
log.blank();
|
|
2862
|
-
log.success(
|
|
3045
|
+
log.success(
|
|
3046
|
+
`Memory config found (${location}) but ${mcpMissing ? "MCP server not registered" : "database not set up"}.`
|
|
3047
|
+
);
|
|
2863
3048
|
log.info("Run `claude-launchpad memory install` to complete setup.");
|
|
2864
3049
|
log.blank();
|
|
2865
3050
|
} else {
|
|
2866
3051
|
log.blank();
|
|
2867
|
-
log.step(
|
|
3052
|
+
log.step(
|
|
3053
|
+
"Claude doesn't have a knowledge base for this project yet."
|
|
3054
|
+
);
|
|
2868
3055
|
log.blank();
|
|
2869
3056
|
log.info("After setup, Claude will:");
|
|
2870
|
-
log.info(
|
|
2871
|
-
|
|
2872
|
-
|
|
3057
|
+
log.info(
|
|
3058
|
+
" - Remember decisions, gotchas, and learnings across sessions"
|
|
3059
|
+
);
|
|
3060
|
+
log.info(
|
|
3061
|
+
" - Automatically recall relevant context when you start a session"
|
|
3062
|
+
);
|
|
3063
|
+
log.info(
|
|
3064
|
+
" - Save important facts as you work, so nothing gets lost"
|
|
3065
|
+
);
|
|
2873
3066
|
log.blank();
|
|
2874
3067
|
}
|
|
2875
3068
|
const proceed = await confirm2({
|
|
@@ -2880,29 +3073,51 @@ function createMemoryCommand() {
|
|
|
2880
3073
|
log.info("Skipped.");
|
|
2881
3074
|
return;
|
|
2882
3075
|
}
|
|
2883
|
-
const { runInstall } = await import("./install-
|
|
3076
|
+
const { runInstall } = await import("./install-D32PV7SF.js");
|
|
2884
3077
|
await runInstall({});
|
|
2885
3078
|
} else {
|
|
2886
|
-
const { requireMemoryDeps } = await import("./require-deps-
|
|
3079
|
+
const { requireMemoryDeps } = await import("./require-deps-WDMHDGBN.js");
|
|
2887
3080
|
await requireMemoryDeps();
|
|
2888
|
-
const { runStats } = await import("./stats-
|
|
3081
|
+
const { runStats } = await import("./stats-77BYLKYP.js");
|
|
2889
3082
|
await runStats({});
|
|
2890
3083
|
}
|
|
2891
3084
|
});
|
|
2892
3085
|
memory.addCommand(
|
|
2893
|
-
new Command4("install").description(
|
|
3086
|
+
new Command4("install").description(
|
|
3087
|
+
"Install (or re-install) the knowledge base for this project"
|
|
3088
|
+
).option("--db-path <path>", "Override the default data directory").option(
|
|
3089
|
+
"-y, --yes",
|
|
3090
|
+
"Non-interactive: accept defaults (shared placement)"
|
|
3091
|
+
).action(async (opts) => {
|
|
2894
3092
|
try {
|
|
2895
|
-
const { runInstall } = await import("./install-
|
|
2896
|
-
await runInstall({
|
|
3093
|
+
const { runInstall } = await import("./install-D32PV7SF.js");
|
|
3094
|
+
await runInstall({
|
|
3095
|
+
...opts.dbPath ? { dbPath: opts.dbPath } : {},
|
|
3096
|
+
yes: opts.yes === true
|
|
3097
|
+
});
|
|
2897
3098
|
} catch (err) {
|
|
2898
3099
|
log.error(err instanceof Error ? err.message : String(err));
|
|
2899
3100
|
process.exitCode = 1;
|
|
2900
3101
|
}
|
|
2901
3102
|
})
|
|
2902
3103
|
);
|
|
3104
|
+
memory.addCommand(
|
|
3105
|
+
new Command4("stats").description("Show memory counts, health, and injection stats").option("--json", "JSON output").action(async (opts) => {
|
|
3106
|
+
const { requireMemoryDeps } = await import("./require-deps-WDMHDGBN.js");
|
|
3107
|
+
await requireMemoryDeps();
|
|
3108
|
+
const { runStats } = await import("./stats-77BYLKYP.js");
|
|
3109
|
+
await runStats(opts);
|
|
3110
|
+
})
|
|
3111
|
+
);
|
|
3112
|
+
memory.addCommand(
|
|
3113
|
+
new Command4("doctor").description("Diagnose the memory setup (DB, hooks, MCP registration)").option("--json", "JSON output").action(async (opts) => {
|
|
3114
|
+
const { runMemoryDoctor } = await import("./doctor-DCHFJ3XV.js");
|
|
3115
|
+
await runMemoryDoctor(opts);
|
|
3116
|
+
})
|
|
3117
|
+
);
|
|
2903
3118
|
memory.addCommand(
|
|
2904
3119
|
new Command4("context").description("Load session context (hook handler)").option("--json", "JSON output").action(async (opts) => {
|
|
2905
|
-
const { runContext } = await import("./context-
|
|
3120
|
+
const { runContext } = await import("./context-YIPO4LBS.js");
|
|
2906
3121
|
await runContext(opts);
|
|
2907
3122
|
}).helpCommand(false),
|
|
2908
3123
|
{ hidden: true }
|
|
@@ -2917,29 +3132,34 @@ function createMemoryCommand() {
|
|
|
2917
3132
|
memory.addCommand(
|
|
2918
3133
|
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) => {
|
|
2919
3134
|
await handleSyncErrors(async () => {
|
|
2920
|
-
const { runPush } = await import("./push-
|
|
3135
|
+
const { runPush } = await import("./push-U4IVTFOU.js");
|
|
2921
3136
|
await runPush(opts);
|
|
2922
3137
|
});
|
|
2923
3138
|
})
|
|
2924
3139
|
);
|
|
2925
3140
|
memory.addCommand(
|
|
2926
|
-
new Command4("pull").description("Pull current project's memories from GitHub Gist").option("--all", "Pull all projects").option(
|
|
3141
|
+
new Command4("pull").description("Pull current project's memories from GitHub Gist").option("--all", "Pull all projects").option(
|
|
3142
|
+
"-y, --yes",
|
|
3143
|
+
"Non-interactive (accepted for symmetry with push; pull never prompts)"
|
|
3144
|
+
).action(async (opts) => {
|
|
2927
3145
|
await handleSyncErrors(async () => {
|
|
2928
|
-
const { runPull } = await import("./pull-
|
|
3146
|
+
const { runPull } = await import("./pull-YUQTDRUP.js");
|
|
2929
3147
|
await runPull(opts);
|
|
2930
3148
|
});
|
|
2931
3149
|
})
|
|
2932
3150
|
);
|
|
2933
|
-
const sync = new Command4("sync").description(
|
|
3151
|
+
const sync = new Command4("sync").description(
|
|
3152
|
+
"Sync memories with the gist (pull + push); subcommands manage sync state"
|
|
3153
|
+
).option("--all", "Sync all projects").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
|
|
2934
3154
|
await handleSyncErrors(async () => {
|
|
2935
|
-
const { runSync } = await import("./sync-
|
|
3155
|
+
const { runSync } = await import("./sync-DTCWK2CY.js");
|
|
2936
3156
|
await runSync(opts);
|
|
2937
3157
|
});
|
|
2938
3158
|
});
|
|
2939
3159
|
sync.addCommand(
|
|
2940
3160
|
new Command4("status").description("Show local vs remote memory counts per project").action(async () => {
|
|
2941
3161
|
await handleSyncErrors(async () => {
|
|
2942
|
-
const { runSyncStatus } = await import("./sync-status-
|
|
3162
|
+
const { runSyncStatus } = await import("./sync-status-2V2RCYZO.js");
|
|
2943
3163
|
await runSyncStatus();
|
|
2944
3164
|
});
|
|
2945
3165
|
})
|
|
@@ -2947,7 +3167,7 @@ function createMemoryCommand() {
|
|
|
2947
3167
|
sync.addCommand(
|
|
2948
3168
|
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) => {
|
|
2949
3169
|
await handleSyncErrors(async () => {
|
|
2950
|
-
const { runSyncClean } = await import("./sync-clean-
|
|
3170
|
+
const { runSyncClean } = await import("./sync-clean-ACZCB3NZ.js");
|
|
2951
3171
|
await runSyncClean(project, opts);
|
|
2952
3172
|
});
|
|
2953
3173
|
})
|
|
@@ -2957,7 +3177,7 @@ function createMemoryCommand() {
|
|
|
2957
3177
|
}
|
|
2958
3178
|
|
|
2959
3179
|
// src/cli.ts
|
|
2960
|
-
var program = new Command5().name("claude-launchpad").description("Score your Claude Code config, fix the gaps, prove Claude follows your rules.").version("1.
|
|
3180
|
+
var program = new Command5().name("claude-launchpad").description("Score your Claude Code config, fix the gaps, prove Claude follows your rules.").version("1.14.0", "-v, --version").action(async () => {
|
|
2961
3181
|
const hasConfig = await fileExists(join13(process.cwd(), "CLAUDE.md")) || await fileExists(join13(process.cwd(), ".claude", "settings.json"));
|
|
2962
3182
|
if (hasConfig) {
|
|
2963
3183
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|