claude-launchpad 1.14.0 → 1.15.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/dist/{chunk-D6RAMWH6.js → chunk-7KB5YGQZ.js} +2 -2
- package/dist/{chunk-UN43OVRW.js → chunk-DLDVXHI3.js} +2 -2
- package/dist/{chunk-M6GVFN67.js → chunk-IPGNXDJF.js} +2 -2
- package/dist/{chunk-VF7U63AI.js → chunk-LCKV24Q3.js} +3 -3
- package/dist/{chunk-OPORVSAF.js → chunk-MX3T2VEX.js} +3 -3
- package/dist/{chunk-QEPE3WVF.js → chunk-U2TFIUGE.js} +57 -5
- package/dist/chunk-U2TFIUGE.js.map +1 -0
- package/dist/cli.js +135 -61
- package/dist/cli.js.map +1 -1
- package/dist/commands/memory/server.js +4 -4
- package/dist/{context-YIPO4LBS.js → context-3GHG7KW6.js} +6 -6
- package/dist/{doctor-DCHFJ3XV.js → doctor-EKGJ2YAO.js} +4 -4
- package/dist/{install-D32PV7SF.js → install-543ZKMXX.js} +6 -6
- package/dist/{pull-YUQTDRUP.js → pull-ULSZEVCR.js} +8 -8
- package/dist/{push-U4IVTFOU.js → push-JXCWX4NY.js} +8 -8
- package/dist/{require-deps-WDMHDGBN.js → require-deps-AEDO5YRM.js} +3 -3
- package/dist/{stats-77BYLKYP.js → stats-63L7C24W.js} +7 -7
- package/dist/{sync-DTCWK2CY.js → sync-QTJ6BXQ4.js} +5 -5
- package/dist/{sync-clean-ACZCB3NZ.js → sync-clean-OJEK4XH4.js} +3 -3
- package/dist/{sync-status-2V2RCYZO.js → sync-status-EAX527SC.js} +8 -8
- package/dist/{tui-HVJNLRY2.js → tui-3KITZCNS.js} +5 -5
- package/package.json +1 -1
- package/dist/chunk-QEPE3WVF.js.map +0 -1
- /package/dist/{chunk-D6RAMWH6.js.map → chunk-7KB5YGQZ.js.map} +0 -0
- /package/dist/{chunk-UN43OVRW.js.map → chunk-DLDVXHI3.js.map} +0 -0
- /package/dist/{chunk-M6GVFN67.js.map → chunk-IPGNXDJF.js.map} +0 -0
- /package/dist/{chunk-VF7U63AI.js.map → chunk-LCKV24Q3.js.map} +0 -0
- /package/dist/{chunk-OPORVSAF.js.map → chunk-MX3T2VEX.js.map} +0 -0
- /package/dist/{context-YIPO4LBS.js.map → context-3GHG7KW6.js.map} +0 -0
- /package/dist/{doctor-DCHFJ3XV.js.map → doctor-EKGJ2YAO.js.map} +0 -0
- /package/dist/{install-D32PV7SF.js.map → install-543ZKMXX.js.map} +0 -0
- /package/dist/{pull-YUQTDRUP.js.map → pull-ULSZEVCR.js.map} +0 -0
- /package/dist/{push-U4IVTFOU.js.map → push-JXCWX4NY.js.map} +0 -0
- /package/dist/{require-deps-WDMHDGBN.js.map → require-deps-AEDO5YRM.js.map} +0 -0
- /package/dist/{stats-77BYLKYP.js.map → stats-63L7C24W.js.map} +0 -0
- /package/dist/{sync-DTCWK2CY.js.map → sync-QTJ6BXQ4.js.map} +0 -0
- /package/dist/{sync-clean-ACZCB3NZ.js.map → sync-clean-OJEK4XH4.js.map} +0 -0
- /package/dist/{sync-status-2V2RCYZO.js.map → sync-status-EAX527SC.js.map} +0 -0
- /package/dist/{tui-HVJNLRY2.js.map → tui-3KITZCNS.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
readSyncConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IPGNXDJF.js";
|
|
5
5
|
import {
|
|
6
6
|
BACKLOG_CONTENT,
|
|
7
7
|
ENHANCE_SKILL_VERSION,
|
|
8
|
+
FORCE_PUSH_ERE,
|
|
8
9
|
LP_STUB_OPEN,
|
|
9
10
|
OFF_LIMITS_CONTENT,
|
|
10
11
|
SESSION_START_CONTENT,
|
|
@@ -40,11 +41,11 @@ import {
|
|
|
40
41
|
sprintReviewsContent,
|
|
41
42
|
writeSprintHygieneScripts,
|
|
42
43
|
writeWorkflowCheckScript
|
|
43
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-U2TFIUGE.js";
|
|
44
45
|
|
|
45
46
|
// src/cli.ts
|
|
46
47
|
import { Command as Command5 } from "commander";
|
|
47
|
-
import { join as
|
|
48
|
+
import { join as join14 } from "path";
|
|
48
49
|
|
|
49
50
|
// src/commands/init/index.ts
|
|
50
51
|
import { Command } from "commander";
|
|
@@ -95,7 +96,8 @@ ${STOP_AND_SWARM_CONTENT}`);
|
|
|
95
96
|
sections.push("", `## Off-Limits
|
|
96
97
|
${OFF_LIMITS_CONTENT}`);
|
|
97
98
|
sections.push("", `## Key Decisions
|
|
98
|
-
<!--
|
|
99
|
+
<!-- Append one entry per non-obvious choice, at the moment it's made \u2014 not at sprint close: -->
|
|
100
|
+
<!-- YYYY-MM-DD \u2014 Chose X over Y because Z. Revisit if W. -->`);
|
|
99
101
|
return sections.join("\n") + "\n";
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -144,7 +146,7 @@ function generateSettings(detected) {
|
|
|
144
146
|
matcher: "Bash",
|
|
145
147
|
hooks: [{
|
|
146
148
|
type: "command",
|
|
147
|
-
command: `cmd=${jqField("command")}; echo "$cmd" | grep -qE 'rm\\s+-rf\\s+/|DROP\\s+TABLE|DROP\\s+DATABASE
|
|
149
|
+
command: `cmd=${jqField("command")}; echo "$cmd" | grep -qE 'rm\\s+-rf\\s+/|DROP\\s+TABLE|DROP\\s+DATABASE|${FORCE_PUSH_ERE}' && { echo 'BLOCKED: Destructive command detected' >&2; exit 2; }; exit 0`
|
|
148
150
|
}]
|
|
149
151
|
});
|
|
150
152
|
const editWriteHooks = [];
|
|
@@ -905,7 +907,28 @@ async function analyzeHooks(config, projectRoot = "") {
|
|
|
905
907
|
});
|
|
906
908
|
return { name: "Hooks", issues, score: 30 };
|
|
907
909
|
}
|
|
908
|
-
const
|
|
910
|
+
const hasStaleForcePattern = config.hooks.some(
|
|
911
|
+
(h) => h.command?.includes("push.*--force|push.*-f")
|
|
912
|
+
);
|
|
913
|
+
if (hasStaleForcePattern) {
|
|
914
|
+
issues.push({
|
|
915
|
+
analyzer: "Hooks",
|
|
916
|
+
severity: "low",
|
|
917
|
+
message: "Force-push guard uses the outdated pattern \u2014 it false-positives on unrelated commands (git stash push, --frozen-lockfile, filenames)",
|
|
918
|
+
fix: "Run `doctor --fix` to upgrade it to the anchored pattern"
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
const formatPatterns = [
|
|
922
|
+
"format",
|
|
923
|
+
"prettier",
|
|
924
|
+
"gofmt",
|
|
925
|
+
"rustfmt",
|
|
926
|
+
"rubocop",
|
|
927
|
+
"pint",
|
|
928
|
+
"ktlint",
|
|
929
|
+
"swift-format",
|
|
930
|
+
"dotnet format"
|
|
931
|
+
];
|
|
909
932
|
const hasPostFormat = hooks.some(
|
|
910
933
|
(h) => h.event === "PostToolUse" && h.matcher?.includes("Write") && formatPatterns.some((p) => h.command?.includes(p))
|
|
911
934
|
);
|
|
@@ -1047,10 +1070,14 @@ async function analyzeHooks(config, projectRoot = "") {
|
|
|
1047
1070
|
}
|
|
1048
1071
|
async function hasStaleHygieneScript(projectRoot) {
|
|
1049
1072
|
const { readFile: readFile7 } = await import("fs/promises");
|
|
1050
|
-
const { join:
|
|
1073
|
+
const { join: join15 } = await import("path");
|
|
1051
1074
|
for (const name of ["workflow-check.sh", "sprint-open-check.sh"]) {
|
|
1052
|
-
const content = await readFile7(
|
|
1053
|
-
|
|
1075
|
+
const content = await readFile7(
|
|
1076
|
+
join15(projectRoot, ".claude", "hooks", name),
|
|
1077
|
+
"utf-8"
|
|
1078
|
+
).catch(() => null);
|
|
1079
|
+
if (content !== null && !content.includes("hookSpecificOutput"))
|
|
1080
|
+
return true;
|
|
1054
1081
|
}
|
|
1055
1082
|
return false;
|
|
1056
1083
|
}
|
|
@@ -1480,6 +1507,11 @@ function extractAllow(settings) {
|
|
|
1480
1507
|
return Array.isArray(allow) ? allow.filter((e) => typeof e === "string") : [];
|
|
1481
1508
|
}
|
|
1482
1509
|
|
|
1510
|
+
// src/commands/doctor/analyzers/quality.ts
|
|
1511
|
+
import { execSync } from "child_process";
|
|
1512
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1513
|
+
import { join as join6 } from "path";
|
|
1514
|
+
|
|
1483
1515
|
// src/commands/doctor/analyzers/hook-resolver.ts
|
|
1484
1516
|
import { readFile as readFile3, realpath } from "fs/promises";
|
|
1485
1517
|
import { resolve as resolve2, sep } from "path";
|
|
@@ -1894,7 +1926,10 @@ function documentSatisfiesIntent(sections, rule) {
|
|
|
1894
1926
|
|
|
1895
1927
|
// src/commands/doctor/analyzers/quality.ts
|
|
1896
1928
|
var VAGUE_PATTERNS = [
|
|
1897
|
-
{
|
|
1929
|
+
{
|
|
1930
|
+
pattern: /write (good|clean|quality|nice) code/i,
|
|
1931
|
+
label: "write good code"
|
|
1932
|
+
},
|
|
1898
1933
|
{ pattern: /be (careful|thorough|diligent)/i, label: "be careful" },
|
|
1899
1934
|
{ pattern: /follow best practices/i, label: "follow best practices" },
|
|
1900
1935
|
{ pattern: /make sure (everything|it) works/i, label: "make sure it works" }
|
|
@@ -1977,17 +2012,56 @@ async function analyzeQuality(config, projectRoot) {
|
|
|
1977
2012
|
fix: "Run `doctor --fix` to collapse them"
|
|
1978
2013
|
});
|
|
1979
2014
|
}
|
|
2015
|
+
if (isKeyDecisionsPlaceholder(content) && commitCount(projectRoot) >= 20) {
|
|
2016
|
+
issues.push({
|
|
2017
|
+
analyzer: "Quality",
|
|
2018
|
+
severity: "low",
|
|
2019
|
+
message: "Key Decisions is still placeholder-only after 20+ commits \u2014 decisions are being made but not logged",
|
|
2020
|
+
fix: "Append entries at decision time: `YYYY-MM-DD \u2014 Chose X over Y because Z. Revisit if W.`"
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
1980
2023
|
const criticals = issues.filter((i) => i.severity === "critical").length;
|
|
1981
2024
|
const highs = issues.filter((i) => i.severity === "high").length;
|
|
1982
2025
|
const mediums = issues.filter((i) => i.severity === "medium").length;
|
|
1983
2026
|
const lows = issues.filter((i) => i.severity === "low").length;
|
|
1984
|
-
const score = Math.max(
|
|
2027
|
+
const score = Math.max(
|
|
2028
|
+
0,
|
|
2029
|
+
100 - criticals * 40 - highs * 30 - mediums * 15 - lows * 5
|
|
2030
|
+
);
|
|
1985
2031
|
return { name: "CLAUDE.md Quality", issues, score };
|
|
1986
2032
|
}
|
|
2033
|
+
function isKeyDecisionsPlaceholder(content) {
|
|
2034
|
+
const lines = content.split("\n");
|
|
2035
|
+
const start = lines.findIndex((l) => /^## Key Decisions\s*$/.test(l));
|
|
2036
|
+
if (start === -1) return false;
|
|
2037
|
+
let end = lines.length;
|
|
2038
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
2039
|
+
if (/^## /.test(lines[i])) {
|
|
2040
|
+
end = i;
|
|
2041
|
+
break;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
const body = lines.slice(start + 1, end).join("\n").replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
2045
|
+
return body.length === 0;
|
|
2046
|
+
}
|
|
2047
|
+
function commitCount(projectRoot) {
|
|
2048
|
+
if (!existsSync2(join6(projectRoot, ".git"))) return 0;
|
|
2049
|
+
try {
|
|
2050
|
+
return parseInt(
|
|
2051
|
+
execSync("git rev-list --count HEAD", {
|
|
2052
|
+
cwd: projectRoot,
|
|
2053
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
2054
|
+
}).toString().trim(),
|
|
2055
|
+
10
|
|
2056
|
+
) || 0;
|
|
2057
|
+
} catch {
|
|
2058
|
+
return 0;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
1987
2061
|
|
|
1988
2062
|
// src/commands/doctor/analyzers/workflow.ts
|
|
1989
2063
|
import { readFile as readFile4 } from "fs/promises";
|
|
1990
|
-
import { join as
|
|
2064
|
+
import { join as join7 } from "path";
|
|
1991
2065
|
var WP_FIELDS = [
|
|
1992
2066
|
"Priority:",
|
|
1993
2067
|
"Proposed:",
|
|
@@ -2000,7 +2074,7 @@ var WP_FIELDS = [
|
|
|
2000
2074
|
var STALE_P0_DAYS = 14;
|
|
2001
2075
|
var STALE_CHANGELOG_DAYS = 30;
|
|
2002
2076
|
async function analyzeWorkflow(projectRoot, now = /* @__PURE__ */ new Date()) {
|
|
2003
|
-
const backlog = await readFile4(
|
|
2077
|
+
const backlog = await readFile4(join7(projectRoot, "BACKLOG.md"), "utf-8").catch(() => null);
|
|
2004
2078
|
if (backlog === null) return null;
|
|
2005
2079
|
const issues = [];
|
|
2006
2080
|
const pSections = extractPSections(backlog);
|
|
@@ -2081,7 +2155,7 @@ function daysBetween(isoDate, now) {
|
|
|
2081
2155
|
|
|
2082
2156
|
// src/commands/doctor/watcher.ts
|
|
2083
2157
|
import { readdir as readdir2, stat } from "fs/promises";
|
|
2084
|
-
import { join as
|
|
2158
|
+
import { join as join8 } from "path";
|
|
2085
2159
|
async function watchConfig(projectRoot) {
|
|
2086
2160
|
await runAndDisplay(projectRoot);
|
|
2087
2161
|
log.blank();
|
|
@@ -2104,16 +2178,16 @@ async function watchConfig(projectRoot) {
|
|
|
2104
2178
|
}
|
|
2105
2179
|
async function getFileSnapshot(projectRoot) {
|
|
2106
2180
|
const files = [
|
|
2107
|
-
|
|
2108
|
-
|
|
2181
|
+
join8(projectRoot, "CLAUDE.md"),
|
|
2182
|
+
join8(projectRoot, ".claudeignore")
|
|
2109
2183
|
];
|
|
2110
|
-
const claudeDir =
|
|
2184
|
+
const claudeDir = join8(projectRoot, ".claude");
|
|
2111
2185
|
try {
|
|
2112
2186
|
const entries = await readdir2(claudeDir, { withFileTypes: true, recursive: true });
|
|
2113
2187
|
for (const entry of entries) {
|
|
2114
2188
|
if (entry.isFile()) {
|
|
2115
2189
|
const parentPath = entry.parentPath ?? claudeDir;
|
|
2116
|
-
files.push(
|
|
2190
|
+
files.push(join8(parentPath, entry.name));
|
|
2117
2191
|
}
|
|
2118
2192
|
}
|
|
2119
2193
|
} catch {
|
|
@@ -2257,11 +2331,11 @@ import { select as select2 } from "@inquirer/prompts";
|
|
|
2257
2331
|
import ora from "ora";
|
|
2258
2332
|
import chalk2 from "chalk";
|
|
2259
2333
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
2260
|
-
import { join as
|
|
2334
|
+
import { join as join12 } from "path";
|
|
2261
2335
|
|
|
2262
2336
|
// src/commands/eval/loader.ts
|
|
2263
2337
|
import { readFile as readFile5, readdir as readdir3 } from "fs/promises";
|
|
2264
|
-
import { join as
|
|
2338
|
+
import { join as join9, resolve as resolve3, dirname as dirname2 } from "path";
|
|
2265
2339
|
import { fileURLToPath } from "url";
|
|
2266
2340
|
import { parse as parseYaml } from "yaml";
|
|
2267
2341
|
|
|
@@ -2390,7 +2464,7 @@ async function findScenariosDir() {
|
|
|
2390
2464
|
async function loadScenarios(options) {
|
|
2391
2465
|
const { suite, customPath } = options;
|
|
2392
2466
|
const scenarioDir = customPath ? resolve3(customPath) : await findScenariosDir();
|
|
2393
|
-
const dirs = suite ? [
|
|
2467
|
+
const dirs = suite ? [join9(scenarioDir, suite)] : await getSubdirectories(scenarioDir);
|
|
2394
2468
|
const allDirs = [scenarioDir, ...dirs];
|
|
2395
2469
|
const scenarios = [];
|
|
2396
2470
|
for (const dir of allDirs) {
|
|
@@ -2412,7 +2486,7 @@ async function loadScenarios(options) {
|
|
|
2412
2486
|
async function getSubdirectories(dir) {
|
|
2413
2487
|
try {
|
|
2414
2488
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
2415
|
-
return entries.filter((e) => e.isDirectory()).map((e) =>
|
|
2489
|
+
return entries.filter((e) => e.isDirectory()).map((e) => join9(dir, e.name));
|
|
2416
2490
|
} catch {
|
|
2417
2491
|
return [];
|
|
2418
2492
|
}
|
|
@@ -2420,7 +2494,7 @@ async function getSubdirectories(dir) {
|
|
|
2420
2494
|
async function listYamlFiles(dir) {
|
|
2421
2495
|
try {
|
|
2422
2496
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
2423
|
-
return entries.filter((e) => e.isFile() && (e.name.endsWith(".yaml") || e.name.endsWith(".yml"))).map((e) =>
|
|
2497
|
+
return entries.filter((e) => e.isFile() && (e.name.endsWith(".yaml") || e.name.endsWith(".yml"))).map((e) => join9(dir, e.name));
|
|
2424
2498
|
} catch {
|
|
2425
2499
|
return [];
|
|
2426
2500
|
}
|
|
@@ -2432,7 +2506,7 @@ function resolveRuns(scenarioRuns, cliRuns, userChoseRuns) {
|
|
|
2432
2506
|
|
|
2433
2507
|
// src/commands/eval/runner.ts
|
|
2434
2508
|
import { mkdir as mkdir2, writeFile as writeFile2, rm, cp } from "fs/promises";
|
|
2435
|
-
import { join as
|
|
2509
|
+
import { join as join11, dirname as dirname3 } from "path";
|
|
2436
2510
|
import { tmpdir as tmpdir2 } from "os";
|
|
2437
2511
|
import { randomUUID } from "crypto";
|
|
2438
2512
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -2440,7 +2514,7 @@ import { promisify as promisify2 } from "util";
|
|
|
2440
2514
|
|
|
2441
2515
|
// src/commands/eval/checks.ts
|
|
2442
2516
|
import { readFile as readFile6, readdir as readdir4 } from "fs/promises";
|
|
2443
|
-
import { join as
|
|
2517
|
+
import { join as join10 } from "path";
|
|
2444
2518
|
import { tmpdir } from "os";
|
|
2445
2519
|
import { execFile } from "child_process";
|
|
2446
2520
|
import { promisify } from "util";
|
|
@@ -2475,7 +2549,7 @@ async function evaluateSingleCheck(check, sandboxDir, context) {
|
|
|
2475
2549
|
async function checkGrep(check, sandboxDir) {
|
|
2476
2550
|
if (!check.pattern || !check.target) return false;
|
|
2477
2551
|
try {
|
|
2478
|
-
const content = await readFile6(
|
|
2552
|
+
const content = await readFile6(join10(sandboxDir, check.target), "utf-8");
|
|
2479
2553
|
let found;
|
|
2480
2554
|
try {
|
|
2481
2555
|
found = new RegExp(check.pattern).test(content);
|
|
@@ -2490,7 +2564,7 @@ async function checkGrep(check, sandboxDir) {
|
|
|
2490
2564
|
async function checkFilePresence(check, sandboxDir) {
|
|
2491
2565
|
if (!check.target) return false;
|
|
2492
2566
|
try {
|
|
2493
|
-
await readFile6(
|
|
2567
|
+
await readFile6(join10(sandboxDir, check.target));
|
|
2494
2568
|
return check.expect === "present";
|
|
2495
2569
|
} catch {
|
|
2496
2570
|
return check.expect === "absent";
|
|
@@ -2500,7 +2574,7 @@ async function checkMaxLines(check, sandboxDir) {
|
|
|
2500
2574
|
if (!check.target) return false;
|
|
2501
2575
|
const maxLines = parseInt(check.pattern ?? "800", 10);
|
|
2502
2576
|
try {
|
|
2503
|
-
const files = await listAllFiles(
|
|
2577
|
+
const files = await listAllFiles(join10(sandboxDir, check.target));
|
|
2504
2578
|
for (const file of files) {
|
|
2505
2579
|
const content = await readFile6(file, "utf-8");
|
|
2506
2580
|
if (content.split("\n").length > maxLines) {
|
|
@@ -2576,7 +2650,7 @@ async function listAllFiles(dir) {
|
|
|
2576
2650
|
try {
|
|
2577
2651
|
const entries = await readdir4(dir, { withFileTypes: true });
|
|
2578
2652
|
for (const entry of entries) {
|
|
2579
|
-
const fullPath =
|
|
2653
|
+
const fullPath = join10(dir, entry.name);
|
|
2580
2654
|
if (entry.isDirectory()) {
|
|
2581
2655
|
results.push(...await listAllFiles(fullPath));
|
|
2582
2656
|
} else {
|
|
@@ -2591,7 +2665,7 @@ async function listAllFiles(dir) {
|
|
|
2591
2665
|
// src/commands/eval/runner.ts
|
|
2592
2666
|
var exec2 = promisify2(execFile2);
|
|
2593
2667
|
async function runScenario(scenario, options) {
|
|
2594
|
-
const sandboxDir =
|
|
2668
|
+
const sandboxDir = join11(tmpdir2(), `claude-eval-${randomUUID()}`);
|
|
2595
2669
|
try {
|
|
2596
2670
|
await setupSandbox(sandboxDir, scenario, options.projectRoot);
|
|
2597
2671
|
const transcript = await runClaudeInSandbox(sandboxDir, scenario.prompt, options.timeout, options.model);
|
|
@@ -2617,14 +2691,14 @@ async function runScenarioWithRetries(scenario, options) {
|
|
|
2617
2691
|
async function setupSandbox(sandboxDir, scenario, projectRoot) {
|
|
2618
2692
|
await mkdir2(sandboxDir, { recursive: true });
|
|
2619
2693
|
for (const file of scenario.setup.files) {
|
|
2620
|
-
const filePath =
|
|
2694
|
+
const filePath = join11(sandboxDir, file.path);
|
|
2621
2695
|
await mkdir2(dirname3(filePath), { recursive: true });
|
|
2622
2696
|
await writeFile2(filePath, file.content);
|
|
2623
2697
|
}
|
|
2624
2698
|
await copyProjectConfig(sandboxDir, projectRoot);
|
|
2625
2699
|
if (scenario.setup.instructions) {
|
|
2626
2700
|
await writeFile2(
|
|
2627
|
-
|
|
2701
|
+
join11(sandboxDir, "CLAUDE.md"),
|
|
2628
2702
|
`# Eval Scenario
|
|
2629
2703
|
|
|
2630
2704
|
${scenario.setup.instructions}
|
|
@@ -2645,20 +2719,20 @@ ${scenario.setup.instructions}
|
|
|
2645
2719
|
], { cwd: sandboxDir });
|
|
2646
2720
|
}
|
|
2647
2721
|
async function copyProjectConfig(sandboxDir, projectRoot) {
|
|
2648
|
-
const claudeDir =
|
|
2649
|
-
const sandboxClaudeDir =
|
|
2650
|
-
const settingsPath =
|
|
2722
|
+
const claudeDir = join11(projectRoot, ".claude");
|
|
2723
|
+
const sandboxClaudeDir = join11(sandboxDir, ".claude");
|
|
2724
|
+
const settingsPath = join11(claudeDir, "settings.json");
|
|
2651
2725
|
if (await fileExists(settingsPath)) {
|
|
2652
2726
|
await mkdir2(sandboxClaudeDir, { recursive: true });
|
|
2653
|
-
await cp(settingsPath,
|
|
2727
|
+
await cp(settingsPath, join11(sandboxClaudeDir, "settings.json"));
|
|
2654
2728
|
}
|
|
2655
|
-
const rulesDir =
|
|
2729
|
+
const rulesDir = join11(claudeDir, "rules");
|
|
2656
2730
|
if (await fileExists(rulesDir)) {
|
|
2657
|
-
await cp(rulesDir,
|
|
2731
|
+
await cp(rulesDir, join11(sandboxClaudeDir, "rules"), { recursive: true });
|
|
2658
2732
|
}
|
|
2659
|
-
const ignorePath =
|
|
2733
|
+
const ignorePath = join11(projectRoot, ".claudeignore");
|
|
2660
2734
|
if (await fileExists(ignorePath)) {
|
|
2661
|
-
await cp(ignorePath,
|
|
2735
|
+
await cp(ignorePath, join11(sandboxDir, ".claudeignore"));
|
|
2662
2736
|
}
|
|
2663
2737
|
}
|
|
2664
2738
|
async function runClaudeInSandbox(cwd, prompt, timeout, model) {
|
|
@@ -2958,10 +3032,10 @@ async function saveEvalReport(results, projectRoot, suite, model) {
|
|
|
2958
3032
|
lines.push("");
|
|
2959
3033
|
}
|
|
2960
3034
|
}
|
|
2961
|
-
const evalDir =
|
|
3035
|
+
const evalDir = join12(projectRoot, ".claude", "eval");
|
|
2962
3036
|
await mkdir3(evalDir, { recursive: true });
|
|
2963
3037
|
const filename = `eval-${suite ?? "all"}-${timestamp}.md`;
|
|
2964
|
-
await writeFile3(
|
|
3038
|
+
await writeFile3(join12(evalDir, filename), lines.join("\n"));
|
|
2965
3039
|
log.success(`Report saved to .claude/eval/${filename}`);
|
|
2966
3040
|
}
|
|
2967
3041
|
async function checkClaudeCli() {
|
|
@@ -2978,7 +3052,7 @@ async function checkClaudeCli() {
|
|
|
2978
3052
|
|
|
2979
3053
|
// src/commands/memory/index.ts
|
|
2980
3054
|
import { readFileSync as readFileSync2 } from "fs";
|
|
2981
|
-
import { join as
|
|
3055
|
+
import { join as join13 } from "path";
|
|
2982
3056
|
import { Command as Command4 } from "commander";
|
|
2983
3057
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
2984
3058
|
async function handleSyncErrors(fn) {
|
|
@@ -2991,7 +3065,7 @@ async function handleSyncErrors(fn) {
|
|
|
2991
3065
|
}
|
|
2992
3066
|
function isMemoryInstalled() {
|
|
2993
3067
|
const cwd = process.cwd();
|
|
2994
|
-
const hookPresent = hasMemoryHook(
|
|
3068
|
+
const hookPresent = hasMemoryHook(join13(cwd, ".claude", "settings.json")) || hasMemoryHook(join13(cwd, ".claude", "settings.local.json"));
|
|
2995
3069
|
if (!hookPresent) return false;
|
|
2996
3070
|
return isMemoryMcpRegistered(cwd);
|
|
2997
3071
|
}
|
|
@@ -3022,9 +3096,9 @@ function createMemoryCommand() {
|
|
|
3022
3096
|
);
|
|
3023
3097
|
return;
|
|
3024
3098
|
}
|
|
3025
|
-
const { requireMemoryDeps } = await import("./require-deps-
|
|
3099
|
+
const { requireMemoryDeps } = await import("./require-deps-AEDO5YRM.js");
|
|
3026
3100
|
await requireMemoryDeps();
|
|
3027
|
-
const { startTui } = await import("./tui-
|
|
3101
|
+
const { startTui } = await import("./tui-3KITZCNS.js");
|
|
3028
3102
|
await startTui();
|
|
3029
3103
|
return;
|
|
3030
3104
|
}
|
|
@@ -3036,7 +3110,7 @@ function createMemoryCommand() {
|
|
|
3036
3110
|
process.exitCode = 1;
|
|
3037
3111
|
return;
|
|
3038
3112
|
}
|
|
3039
|
-
const { detectExistingSetup } = await import("./install-
|
|
3113
|
+
const { detectExistingSetup } = await import("./install-543ZKMXX.js");
|
|
3040
3114
|
const existing = detectExistingSetup(process.cwd());
|
|
3041
3115
|
const mcpMissing = existing !== null && !isMemoryMcpRegistered(process.cwd());
|
|
3042
3116
|
if (existing) {
|
|
@@ -3073,12 +3147,12 @@ function createMemoryCommand() {
|
|
|
3073
3147
|
log.info("Skipped.");
|
|
3074
3148
|
return;
|
|
3075
3149
|
}
|
|
3076
|
-
const { runInstall } = await import("./install-
|
|
3150
|
+
const { runInstall } = await import("./install-543ZKMXX.js");
|
|
3077
3151
|
await runInstall({});
|
|
3078
3152
|
} else {
|
|
3079
|
-
const { requireMemoryDeps } = await import("./require-deps-
|
|
3153
|
+
const { requireMemoryDeps } = await import("./require-deps-AEDO5YRM.js");
|
|
3080
3154
|
await requireMemoryDeps();
|
|
3081
|
-
const { runStats } = await import("./stats-
|
|
3155
|
+
const { runStats } = await import("./stats-63L7C24W.js");
|
|
3082
3156
|
await runStats({});
|
|
3083
3157
|
}
|
|
3084
3158
|
});
|
|
@@ -3090,7 +3164,7 @@ function createMemoryCommand() {
|
|
|
3090
3164
|
"Non-interactive: accept defaults (shared placement)"
|
|
3091
3165
|
).action(async (opts) => {
|
|
3092
3166
|
try {
|
|
3093
|
-
const { runInstall } = await import("./install-
|
|
3167
|
+
const { runInstall } = await import("./install-543ZKMXX.js");
|
|
3094
3168
|
await runInstall({
|
|
3095
3169
|
...opts.dbPath ? { dbPath: opts.dbPath } : {},
|
|
3096
3170
|
yes: opts.yes === true
|
|
@@ -3103,21 +3177,21 @@ function createMemoryCommand() {
|
|
|
3103
3177
|
);
|
|
3104
3178
|
memory.addCommand(
|
|
3105
3179
|
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-
|
|
3180
|
+
const { requireMemoryDeps } = await import("./require-deps-AEDO5YRM.js");
|
|
3107
3181
|
await requireMemoryDeps();
|
|
3108
|
-
const { runStats } = await import("./stats-
|
|
3182
|
+
const { runStats } = await import("./stats-63L7C24W.js");
|
|
3109
3183
|
await runStats(opts);
|
|
3110
3184
|
})
|
|
3111
3185
|
);
|
|
3112
3186
|
memory.addCommand(
|
|
3113
3187
|
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-
|
|
3188
|
+
const { runMemoryDoctor } = await import("./doctor-EKGJ2YAO.js");
|
|
3115
3189
|
await runMemoryDoctor(opts);
|
|
3116
3190
|
})
|
|
3117
3191
|
);
|
|
3118
3192
|
memory.addCommand(
|
|
3119
3193
|
new Command4("context").description("Load session context (hook handler)").option("--json", "JSON output").action(async (opts) => {
|
|
3120
|
-
const { runContext } = await import("./context-
|
|
3194
|
+
const { runContext } = await import("./context-3GHG7KW6.js");
|
|
3121
3195
|
await runContext(opts);
|
|
3122
3196
|
}).helpCommand(false),
|
|
3123
3197
|
{ hidden: true }
|
|
@@ -3132,7 +3206,7 @@ function createMemoryCommand() {
|
|
|
3132
3206
|
memory.addCommand(
|
|
3133
3207
|
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) => {
|
|
3134
3208
|
await handleSyncErrors(async () => {
|
|
3135
|
-
const { runPush } = await import("./push-
|
|
3209
|
+
const { runPush } = await import("./push-JXCWX4NY.js");
|
|
3136
3210
|
await runPush(opts);
|
|
3137
3211
|
});
|
|
3138
3212
|
})
|
|
@@ -3143,7 +3217,7 @@ function createMemoryCommand() {
|
|
|
3143
3217
|
"Non-interactive (accepted for symmetry with push; pull never prompts)"
|
|
3144
3218
|
).action(async (opts) => {
|
|
3145
3219
|
await handleSyncErrors(async () => {
|
|
3146
|
-
const { runPull } = await import("./pull-
|
|
3220
|
+
const { runPull } = await import("./pull-ULSZEVCR.js");
|
|
3147
3221
|
await runPull(opts);
|
|
3148
3222
|
});
|
|
3149
3223
|
})
|
|
@@ -3152,14 +3226,14 @@ function createMemoryCommand() {
|
|
|
3152
3226
|
"Sync memories with the gist (pull + push); subcommands manage sync state"
|
|
3153
3227
|
).option("--all", "Sync all projects").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
|
|
3154
3228
|
await handleSyncErrors(async () => {
|
|
3155
|
-
const { runSync } = await import("./sync-
|
|
3229
|
+
const { runSync } = await import("./sync-QTJ6BXQ4.js");
|
|
3156
3230
|
await runSync(opts);
|
|
3157
3231
|
});
|
|
3158
3232
|
});
|
|
3159
3233
|
sync.addCommand(
|
|
3160
3234
|
new Command4("status").description("Show local vs remote memory counts per project").action(async () => {
|
|
3161
3235
|
await handleSyncErrors(async () => {
|
|
3162
|
-
const { runSyncStatus } = await import("./sync-status-
|
|
3236
|
+
const { runSyncStatus } = await import("./sync-status-EAX527SC.js");
|
|
3163
3237
|
await runSyncStatus();
|
|
3164
3238
|
});
|
|
3165
3239
|
})
|
|
@@ -3167,7 +3241,7 @@ function createMemoryCommand() {
|
|
|
3167
3241
|
sync.addCommand(
|
|
3168
3242
|
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) => {
|
|
3169
3243
|
await handleSyncErrors(async () => {
|
|
3170
|
-
const { runSyncClean } = await import("./sync-clean-
|
|
3244
|
+
const { runSyncClean } = await import("./sync-clean-OJEK4XH4.js");
|
|
3171
3245
|
await runSyncClean(project, opts);
|
|
3172
3246
|
});
|
|
3173
3247
|
})
|
|
@@ -3178,7 +3252,7 @@ function createMemoryCommand() {
|
|
|
3178
3252
|
|
|
3179
3253
|
// src/cli.ts
|
|
3180
3254
|
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 () => {
|
|
3181
|
-
const hasConfig = await fileExists(
|
|
3255
|
+
const hasConfig = await fileExists(join14(process.cwd(), "CLAUDE.md")) || await fileExists(join14(process.cwd(), ".claude", "settings.json"));
|
|
3182
3256
|
if (hasConfig) {
|
|
3183
3257
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|
|
3184
3258
|
} else {
|