claudekit-cli 4.5.0-dev.4 → 4.5.0-dev.5
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/cli-manifest.json +2 -2
- package/dist/index.js +331 -115
- package/package.json +1 -1
package/cli-manifest.json
CHANGED
package/dist/index.js
CHANGED
|
@@ -64421,7 +64421,7 @@ var package_default;
|
|
|
64421
64421
|
var init_package = __esm(() => {
|
|
64422
64422
|
package_default = {
|
|
64423
64423
|
name: "claudekit-cli",
|
|
64424
|
-
version: "4.5.0-dev.
|
|
64424
|
+
version: "4.5.0-dev.5",
|
|
64425
64425
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
64426
64426
|
type: "module",
|
|
64427
64427
|
repository: {
|
|
@@ -65083,7 +65083,7 @@ import { spawnSync as spawnSync3 } from "node:child_process";
|
|
|
65083
65083
|
import { existsSync as existsSync46, readFileSync as readFileSync14, readdirSync as readdirSync9, statSync as statSync10, writeFileSync as writeFileSync5 } from "node:fs";
|
|
65084
65084
|
import { readdir as readdir17 } from "node:fs/promises";
|
|
65085
65085
|
import { homedir as homedir40, tmpdir } from "node:os";
|
|
65086
|
-
import { dirname as dirname29, join as join65, resolve as resolve33 } from "node:path";
|
|
65086
|
+
import { dirname as dirname29, join as join65, resolve as resolve33, sep as sep11 } from "node:path";
|
|
65087
65087
|
function resolveDoctorCkExecutable(platformName = process.platform) {
|
|
65088
65088
|
return platformName === "win32" ? "ck.cmd" : "ck";
|
|
65089
65089
|
}
|
|
@@ -66085,6 +66085,21 @@ async function countMissingHookFileReferences(projectDir = process.cwd()) {
|
|
|
66085
66085
|
}
|
|
66086
66086
|
return count;
|
|
66087
66087
|
}
|
|
66088
|
+
async function countMissingHookFileReferencesForClaudeDir(claudeDir3, projectRoot = dirname29(claudeDir3)) {
|
|
66089
|
+
const hooksDirPrefix = `${resolve33(claudeDir3, "hooks")}${sep11}`;
|
|
66090
|
+
let count = 0;
|
|
66091
|
+
for (const fileName of ["settings.json", "settings.local.json"]) {
|
|
66092
|
+
const filePath = resolve33(claudeDir3, fileName);
|
|
66093
|
+
if (!existsSync46(filePath))
|
|
66094
|
+
continue;
|
|
66095
|
+
const settings = await SettingsMerger.readSettingsFile(filePath);
|
|
66096
|
+
if (!settings)
|
|
66097
|
+
continue;
|
|
66098
|
+
const descriptor = { path: filePath, label: fileName, root: "$HOME" };
|
|
66099
|
+
count += collectMissingHookReferences(settings, descriptor, projectRoot).filter((finding) => finding.resolvedPath.startsWith(hooksDirPrefix)).length;
|
|
66100
|
+
}
|
|
66101
|
+
return count;
|
|
66102
|
+
}
|
|
66088
66103
|
async function repairMissingHookFileReferences(projectDir = process.cwd()) {
|
|
66089
66104
|
const result = await checkHookFileReferences(projectDir);
|
|
66090
66105
|
if (result.status !== "fail" || !result.fix) {
|
|
@@ -78068,10 +78083,10 @@ __export(exports_worktree_manager, {
|
|
|
78068
78083
|
cleanupAllWorktrees: () => cleanupAllWorktrees
|
|
78069
78084
|
});
|
|
78070
78085
|
import { existsSync as existsSync77 } from "node:fs";
|
|
78071
|
-
import { readFile as
|
|
78072
|
-
import { join as
|
|
78086
|
+
import { readFile as readFile70, writeFile as writeFile41 } from "node:fs/promises";
|
|
78087
|
+
import { join as join159 } from "node:path";
|
|
78073
78088
|
async function createWorktree(projectDir, issueNumber, baseBranch) {
|
|
78074
|
-
const worktreePath =
|
|
78089
|
+
const worktreePath = join159(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
|
|
78075
78090
|
const branchName = `ck-watch/issue-${issueNumber}`;
|
|
78076
78091
|
await spawnAndCollect("git", ["fetch", "origin", baseBranch], projectDir).catch(() => {
|
|
78077
78092
|
logger.warning(`[worktree] Could not fetch origin/${baseBranch}, using local`);
|
|
@@ -78089,7 +78104,7 @@ async function createWorktree(projectDir, issueNumber, baseBranch) {
|
|
|
78089
78104
|
return worktreePath;
|
|
78090
78105
|
}
|
|
78091
78106
|
async function removeWorktree(projectDir, issueNumber) {
|
|
78092
|
-
const worktreePath =
|
|
78107
|
+
const worktreePath = join159(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
|
|
78093
78108
|
const branchName = `ck-watch/issue-${issueNumber}`;
|
|
78094
78109
|
try {
|
|
78095
78110
|
await spawnAndCollect("git", ["worktree", "remove", worktreePath, "--force"], projectDir);
|
|
@@ -78103,7 +78118,7 @@ async function listActiveWorktrees(projectDir) {
|
|
|
78103
78118
|
try {
|
|
78104
78119
|
const output2 = await spawnAndCollect("git", ["worktree", "list", "--porcelain"], projectDir);
|
|
78105
78120
|
const issueNumbers = [];
|
|
78106
|
-
const worktreePrefix =
|
|
78121
|
+
const worktreePrefix = join159(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
|
|
78107
78122
|
for (const line of output2.split(`
|
|
78108
78123
|
`)) {
|
|
78109
78124
|
if (line.startsWith("worktree ")) {
|
|
@@ -78131,16 +78146,16 @@ async function cleanupAllWorktrees(projectDir) {
|
|
|
78131
78146
|
await spawnAndCollect("git", ["worktree", "prune"], projectDir).catch(() => {});
|
|
78132
78147
|
}
|
|
78133
78148
|
async function ensureGitignore(projectDir) {
|
|
78134
|
-
const gitignorePath =
|
|
78149
|
+
const gitignorePath = join159(projectDir, ".gitignore");
|
|
78135
78150
|
try {
|
|
78136
|
-
const content = existsSync77(gitignorePath) ? await
|
|
78151
|
+
const content = existsSync77(gitignorePath) ? await readFile70(gitignorePath, "utf-8") : "";
|
|
78137
78152
|
if (!content.includes(".worktrees")) {
|
|
78138
78153
|
const newContent = content.endsWith(`
|
|
78139
78154
|
`) ? `${content}.worktrees/
|
|
78140
78155
|
` : `${content}
|
|
78141
78156
|
.worktrees/
|
|
78142
78157
|
`;
|
|
78143
|
-
await
|
|
78158
|
+
await writeFile41(gitignorePath, newContent, "utf-8");
|
|
78144
78159
|
logger.info("[worktree] Added .worktrees/ to .gitignore");
|
|
78145
78160
|
}
|
|
78146
78161
|
} catch (err) {
|
|
@@ -78236,9 +78251,9 @@ var init_content_validator = __esm(() => {
|
|
|
78236
78251
|
// src/commands/content/phases/context-cache-manager.ts
|
|
78237
78252
|
import { createHash as createHash9 } from "node:crypto";
|
|
78238
78253
|
import { existsSync as existsSync83, mkdirSync as mkdirSync7, readFileSync as readFileSync22, readdirSync as readdirSync14, statSync as statSync15 } from "node:fs";
|
|
78239
|
-
import { rename as rename16, writeFile as
|
|
78254
|
+
import { rename as rename16, writeFile as writeFile43 } from "node:fs/promises";
|
|
78240
78255
|
import { homedir as homedir54 } from "node:os";
|
|
78241
|
-
import { basename as basename34, join as
|
|
78256
|
+
import { basename as basename34, join as join166 } from "node:path";
|
|
78242
78257
|
function getCachedContext(repoPath) {
|
|
78243
78258
|
const cachePath = getCacheFilePath(repoPath);
|
|
78244
78259
|
if (!existsSync83(cachePath))
|
|
@@ -78263,7 +78278,7 @@ async function saveCachedContext(repoPath, cache5) {
|
|
|
78263
78278
|
}
|
|
78264
78279
|
const cachePath = getCacheFilePath(repoPath);
|
|
78265
78280
|
const tmpPath = `${cachePath}.tmp`;
|
|
78266
|
-
await
|
|
78281
|
+
await writeFile43(tmpPath, JSON.stringify(cache5, null, 2), "utf-8");
|
|
78267
78282
|
await rename16(tmpPath, cachePath);
|
|
78268
78283
|
}
|
|
78269
78284
|
function computeSourceHash(repoPath) {
|
|
@@ -78281,25 +78296,25 @@ function computeSourceHash(repoPath) {
|
|
|
78281
78296
|
}
|
|
78282
78297
|
function getDocSourcePaths(repoPath) {
|
|
78283
78298
|
const paths = [];
|
|
78284
|
-
const docsDir =
|
|
78299
|
+
const docsDir = join166(repoPath, "docs");
|
|
78285
78300
|
if (existsSync83(docsDir)) {
|
|
78286
78301
|
try {
|
|
78287
78302
|
const files = readdirSync14(docsDir);
|
|
78288
78303
|
for (const f3 of files) {
|
|
78289
78304
|
if (f3.endsWith(".md"))
|
|
78290
|
-
paths.push(
|
|
78305
|
+
paths.push(join166(docsDir, f3));
|
|
78291
78306
|
}
|
|
78292
78307
|
} catch {}
|
|
78293
78308
|
}
|
|
78294
|
-
const readme =
|
|
78309
|
+
const readme = join166(repoPath, "README.md");
|
|
78295
78310
|
if (existsSync83(readme))
|
|
78296
78311
|
paths.push(readme);
|
|
78297
|
-
const stylesDir =
|
|
78312
|
+
const stylesDir = join166(repoPath, "assets", "writing-styles");
|
|
78298
78313
|
if (existsSync83(stylesDir)) {
|
|
78299
78314
|
try {
|
|
78300
78315
|
const files = readdirSync14(stylesDir);
|
|
78301
78316
|
for (const f3 of files) {
|
|
78302
|
-
paths.push(
|
|
78317
|
+
paths.push(join166(stylesDir, f3));
|
|
78303
78318
|
}
|
|
78304
78319
|
} catch {}
|
|
78305
78320
|
}
|
|
@@ -78308,11 +78323,11 @@ function getDocSourcePaths(repoPath) {
|
|
|
78308
78323
|
function getCacheFilePath(repoPath) {
|
|
78309
78324
|
const repoName = basename34(repoPath).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
78310
78325
|
const pathHash = createHash9("sha256").update(repoPath).digest("hex").slice(0, 8);
|
|
78311
|
-
return
|
|
78326
|
+
return join166(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
|
|
78312
78327
|
}
|
|
78313
78328
|
var CACHE_DIR, CACHE_TTL_MS5;
|
|
78314
78329
|
var init_context_cache_manager = __esm(() => {
|
|
78315
|
-
CACHE_DIR =
|
|
78330
|
+
CACHE_DIR = join166(homedir54(), ".claudekit", "cache");
|
|
78316
78331
|
CACHE_TTL_MS5 = 24 * 60 * 60 * 1000;
|
|
78317
78332
|
});
|
|
78318
78333
|
|
|
@@ -78493,7 +78508,7 @@ function extractContentFromResponse(response) {
|
|
|
78493
78508
|
// src/commands/content/phases/docs-summarizer.ts
|
|
78494
78509
|
import { execSync as execSync7 } from "node:child_process";
|
|
78495
78510
|
import { existsSync as existsSync84, readFileSync as readFileSync23, readdirSync as readdirSync15 } from "node:fs";
|
|
78496
|
-
import { join as
|
|
78511
|
+
import { join as join167 } from "node:path";
|
|
78497
78512
|
async function summarizeProjectDocs(repoPath, contentLogger) {
|
|
78498
78513
|
const rawContent = collectRawDocs(repoPath);
|
|
78499
78514
|
if (rawContent.total.length < 200) {
|
|
@@ -78547,12 +78562,12 @@ function collectRawDocs(repoPath) {
|
|
|
78547
78562
|
return capped;
|
|
78548
78563
|
};
|
|
78549
78564
|
const docsContent = [];
|
|
78550
|
-
const docsDir =
|
|
78565
|
+
const docsDir = join167(repoPath, "docs");
|
|
78551
78566
|
if (existsSync84(docsDir)) {
|
|
78552
78567
|
try {
|
|
78553
78568
|
const files = readdirSync15(docsDir).filter((f3) => f3.endsWith(".md")).sort();
|
|
78554
78569
|
for (const f3 of files) {
|
|
78555
|
-
const content = readCapped(
|
|
78570
|
+
const content = readCapped(join167(docsDir, f3), 5000);
|
|
78556
78571
|
if (content) {
|
|
78557
78572
|
docsContent.push(`### ${f3}
|
|
78558
78573
|
${content}`);
|
|
@@ -78566,21 +78581,21 @@ ${content}`);
|
|
|
78566
78581
|
let brand = "";
|
|
78567
78582
|
const brandCandidates = ["docs/brand-guidelines.md", "docs/design-guidelines.md"];
|
|
78568
78583
|
for (const p of brandCandidates) {
|
|
78569
|
-
brand = readCapped(
|
|
78584
|
+
brand = readCapped(join167(repoPath, p), 3000);
|
|
78570
78585
|
if (brand)
|
|
78571
78586
|
break;
|
|
78572
78587
|
}
|
|
78573
78588
|
let styles3 = "";
|
|
78574
|
-
const stylesDir =
|
|
78589
|
+
const stylesDir = join167(repoPath, "assets", "writing-styles");
|
|
78575
78590
|
if (existsSync84(stylesDir)) {
|
|
78576
78591
|
try {
|
|
78577
78592
|
const files = readdirSync15(stylesDir).slice(0, 3);
|
|
78578
|
-
styles3 = files.map((f3) => readCapped(
|
|
78593
|
+
styles3 = files.map((f3) => readCapped(join167(stylesDir, f3), 1000)).filter(Boolean).join(`
|
|
78579
78594
|
|
|
78580
78595
|
`);
|
|
78581
78596
|
} catch {}
|
|
78582
78597
|
}
|
|
78583
|
-
const readme = readCapped(
|
|
78598
|
+
const readme = readCapped(join167(repoPath, "README.md"), 3000);
|
|
78584
78599
|
const total = [docs, brand, styles3, readme].join(`
|
|
78585
78600
|
`);
|
|
78586
78601
|
return { docs, brand, styles: styles3, readme, total };
|
|
@@ -78767,9 +78782,9 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
|
|
|
78767
78782
|
import { execSync as execSync8 } from "node:child_process";
|
|
78768
78783
|
import { existsSync as existsSync85, mkdirSync as mkdirSync8, readdirSync as readdirSync16 } from "node:fs";
|
|
78769
78784
|
import { homedir as homedir55 } from "node:os";
|
|
78770
|
-
import { join as
|
|
78785
|
+
import { join as join168 } from "node:path";
|
|
78771
78786
|
async function generatePhoto(_content, context, config, platform18, contentId, contentLogger) {
|
|
78772
|
-
const mediaDir =
|
|
78787
|
+
const mediaDir = join168(config.contentDir.replace(/^~/, homedir55()), "media", String(contentId));
|
|
78773
78788
|
if (!existsSync85(mediaDir)) {
|
|
78774
78789
|
mkdirSync8(mediaDir, { recursive: true });
|
|
78775
78790
|
}
|
|
@@ -78794,7 +78809,7 @@ async function generatePhoto(_content, context, config, platform18, contentId, c
|
|
|
78794
78809
|
const imageFile = files.find((f3) => /\.(png|jpg|jpeg|webp)$/i.test(f3));
|
|
78795
78810
|
if (imageFile) {
|
|
78796
78811
|
const ext2 = imageFile.split(".").pop() ?? "png";
|
|
78797
|
-
return { path:
|
|
78812
|
+
return { path: join168(mediaDir, imageFile), ...dimensions, format: ext2 };
|
|
78798
78813
|
}
|
|
78799
78814
|
contentLogger.warn(`Photo generation produced no image for content ${contentId}`);
|
|
78800
78815
|
return null;
|
|
@@ -78884,7 +78899,7 @@ var init_content_creator = __esm(() => {
|
|
|
78884
78899
|
// src/commands/content/phases/content-logger.ts
|
|
78885
78900
|
import { createWriteStream as createWriteStream4, existsSync as existsSync86, mkdirSync as mkdirSync9, statSync as statSync16 } from "node:fs";
|
|
78886
78901
|
import { homedir as homedir56 } from "node:os";
|
|
78887
|
-
import { join as
|
|
78902
|
+
import { join as join169 } from "node:path";
|
|
78888
78903
|
|
|
78889
78904
|
class ContentLogger {
|
|
78890
78905
|
stream = null;
|
|
@@ -78892,7 +78907,7 @@ class ContentLogger {
|
|
|
78892
78907
|
logDir;
|
|
78893
78908
|
maxBytes;
|
|
78894
78909
|
constructor(maxBytes = 0) {
|
|
78895
|
-
this.logDir =
|
|
78910
|
+
this.logDir = join169(homedir56(), ".claudekit", "logs");
|
|
78896
78911
|
this.maxBytes = maxBytes;
|
|
78897
78912
|
}
|
|
78898
78913
|
init() {
|
|
@@ -78924,7 +78939,7 @@ class ContentLogger {
|
|
|
78924
78939
|
}
|
|
78925
78940
|
}
|
|
78926
78941
|
getLogPath() {
|
|
78927
|
-
return
|
|
78942
|
+
return join169(this.logDir, `content-${this.getDateStr()}.log`);
|
|
78928
78943
|
}
|
|
78929
78944
|
write(level, message) {
|
|
78930
78945
|
this.rotateIfNeeded();
|
|
@@ -78941,18 +78956,18 @@ class ContentLogger {
|
|
|
78941
78956
|
if (dateStr !== this.currentDate) {
|
|
78942
78957
|
this.close();
|
|
78943
78958
|
this.currentDate = dateStr;
|
|
78944
|
-
const logPath =
|
|
78959
|
+
const logPath = join169(this.logDir, `content-${dateStr}.log`);
|
|
78945
78960
|
this.stream = createWriteStream4(logPath, { flags: "a", mode: 384 });
|
|
78946
78961
|
return;
|
|
78947
78962
|
}
|
|
78948
78963
|
if (this.maxBytes > 0 && this.stream) {
|
|
78949
|
-
const logPath =
|
|
78964
|
+
const logPath = join169(this.logDir, `content-${this.currentDate}.log`);
|
|
78950
78965
|
try {
|
|
78951
78966
|
const stat26 = statSync16(logPath);
|
|
78952
78967
|
if (stat26.size >= this.maxBytes) {
|
|
78953
78968
|
this.close();
|
|
78954
78969
|
const suffix = Date.now();
|
|
78955
|
-
const rotatedPath =
|
|
78970
|
+
const rotatedPath = join169(this.logDir, `content-${this.currentDate}-${suffix}.log`);
|
|
78956
78971
|
import("node:fs/promises").then(({ rename: rename17 }) => rename17(logPath, rotatedPath).catch(() => {}));
|
|
78957
78972
|
this.stream = createWriteStream4(logPath, { flags: "w", mode: 384 });
|
|
78958
78973
|
}
|
|
@@ -79223,7 +79238,7 @@ function isNoiseCommit(title, author) {
|
|
|
79223
79238
|
// src/commands/content/phases/change-detector.ts
|
|
79224
79239
|
import { execSync as execSync10, spawnSync as spawnSync9 } from "node:child_process";
|
|
79225
79240
|
import { existsSync as existsSync88, readFileSync as readFileSync24, readdirSync as readdirSync17, statSync as statSync17 } from "node:fs";
|
|
79226
|
-
import { join as
|
|
79241
|
+
import { join as join170 } from "node:path";
|
|
79227
79242
|
function detectCommits(repo, since) {
|
|
79228
79243
|
try {
|
|
79229
79244
|
const fetchUrl = sshToHttps(repo.remoteUrl);
|
|
@@ -79332,7 +79347,7 @@ function detectTags(repo, since) {
|
|
|
79332
79347
|
}
|
|
79333
79348
|
}
|
|
79334
79349
|
function detectCompletedPlans(repo, since) {
|
|
79335
|
-
const plansDir =
|
|
79350
|
+
const plansDir = join170(repo.path, "plans");
|
|
79336
79351
|
if (!existsSync88(plansDir))
|
|
79337
79352
|
return [];
|
|
79338
79353
|
const sinceMs = new Date(since).getTime();
|
|
@@ -79342,7 +79357,7 @@ function detectCompletedPlans(repo, since) {
|
|
|
79342
79357
|
for (const entry of entries) {
|
|
79343
79358
|
if (!entry.isDirectory())
|
|
79344
79359
|
continue;
|
|
79345
|
-
const planFile =
|
|
79360
|
+
const planFile = join170(plansDir, entry.name, "plan.md");
|
|
79346
79361
|
if (!existsSync88(planFile))
|
|
79347
79362
|
continue;
|
|
79348
79363
|
try {
|
|
@@ -79420,7 +79435,7 @@ function classifyCommit(event) {
|
|
|
79420
79435
|
// src/commands/content/phases/repo-discoverer.ts
|
|
79421
79436
|
import { execSync as execSync11 } from "node:child_process";
|
|
79422
79437
|
import { readdirSync as readdirSync18 } from "node:fs";
|
|
79423
|
-
import { join as
|
|
79438
|
+
import { join as join171 } from "node:path";
|
|
79424
79439
|
function discoverRepos2(cwd2) {
|
|
79425
79440
|
const repos = [];
|
|
79426
79441
|
if (isGitRepoRoot(cwd2)) {
|
|
@@ -79433,7 +79448,7 @@ function discoverRepos2(cwd2) {
|
|
|
79433
79448
|
for (const entry of entries) {
|
|
79434
79449
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
79435
79450
|
continue;
|
|
79436
|
-
const dirPath =
|
|
79451
|
+
const dirPath = join171(cwd2, entry.name);
|
|
79437
79452
|
if (isGitRepoRoot(dirPath)) {
|
|
79438
79453
|
const info = getRepoInfo(dirPath);
|
|
79439
79454
|
if (info)
|
|
@@ -80100,12 +80115,12 @@ var init_types6 = __esm(() => {
|
|
|
80100
80115
|
});
|
|
80101
80116
|
|
|
80102
80117
|
// src/commands/content/phases/state-manager.ts
|
|
80103
|
-
import { readFile as
|
|
80104
|
-
import { join as
|
|
80118
|
+
import { readFile as readFile72, rename as rename17, writeFile as writeFile44 } from "node:fs/promises";
|
|
80119
|
+
import { join as join172 } from "node:path";
|
|
80105
80120
|
async function loadContentConfig(projectDir) {
|
|
80106
|
-
const configPath =
|
|
80121
|
+
const configPath = join172(projectDir, CK_CONFIG_FILE2);
|
|
80107
80122
|
try {
|
|
80108
|
-
const raw2 = await
|
|
80123
|
+
const raw2 = await readFile72(configPath, "utf-8");
|
|
80109
80124
|
const json = JSON.parse(raw2);
|
|
80110
80125
|
return ContentConfigSchema.parse(json.content ?? {});
|
|
80111
80126
|
} catch {
|
|
@@ -80113,15 +80128,15 @@ async function loadContentConfig(projectDir) {
|
|
|
80113
80128
|
}
|
|
80114
80129
|
}
|
|
80115
80130
|
async function saveContentConfig(projectDir, config) {
|
|
80116
|
-
const configPath =
|
|
80131
|
+
const configPath = join172(projectDir, CK_CONFIG_FILE2);
|
|
80117
80132
|
const json = await readJsonSafe4(configPath);
|
|
80118
80133
|
json.content = { ...json.content, ...config };
|
|
80119
80134
|
await atomicWrite3(configPath, json);
|
|
80120
80135
|
}
|
|
80121
80136
|
async function loadContentState(projectDir) {
|
|
80122
|
-
const configPath =
|
|
80137
|
+
const configPath = join172(projectDir, CK_CONFIG_FILE2);
|
|
80123
80138
|
try {
|
|
80124
|
-
const raw2 = await
|
|
80139
|
+
const raw2 = await readFile72(configPath, "utf-8");
|
|
80125
80140
|
const json = JSON.parse(raw2);
|
|
80126
80141
|
const contentBlock = json.content ?? {};
|
|
80127
80142
|
return ContentStateSchema.parse(contentBlock.state ?? {});
|
|
@@ -80130,7 +80145,7 @@ async function loadContentState(projectDir) {
|
|
|
80130
80145
|
}
|
|
80131
80146
|
}
|
|
80132
80147
|
async function saveContentState(projectDir, state) {
|
|
80133
|
-
const configPath =
|
|
80148
|
+
const configPath = join172(projectDir, CK_CONFIG_FILE2);
|
|
80134
80149
|
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
|
80135
80150
|
for (const key of Object.keys(state.dailyPostCounts)) {
|
|
80136
80151
|
const dateStr = key.slice(-10);
|
|
@@ -80148,7 +80163,7 @@ async function saveContentState(projectDir, state) {
|
|
|
80148
80163
|
}
|
|
80149
80164
|
async function readJsonSafe4(filePath) {
|
|
80150
80165
|
try {
|
|
80151
|
-
const raw2 = await
|
|
80166
|
+
const raw2 = await readFile72(filePath, "utf-8");
|
|
80152
80167
|
return JSON.parse(raw2);
|
|
80153
80168
|
} catch {
|
|
80154
80169
|
return {};
|
|
@@ -80156,7 +80171,7 @@ async function readJsonSafe4(filePath) {
|
|
|
80156
80171
|
}
|
|
80157
80172
|
async function atomicWrite3(filePath, data) {
|
|
80158
80173
|
const tmpPath = `${filePath}.tmp`;
|
|
80159
|
-
await
|
|
80174
|
+
await writeFile44(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
80160
80175
|
await rename17(tmpPath, filePath);
|
|
80161
80176
|
}
|
|
80162
80177
|
var CK_CONFIG_FILE2 = ".ck.json";
|
|
@@ -80412,7 +80427,7 @@ var init_platform_setup_x = __esm(() => {
|
|
|
80412
80427
|
|
|
80413
80428
|
// src/commands/content/phases/setup-wizard.ts
|
|
80414
80429
|
import { existsSync as existsSync89 } from "node:fs";
|
|
80415
|
-
import { join as
|
|
80430
|
+
import { join as join173 } from "node:path";
|
|
80416
80431
|
async function runSetupWizard2(cwd2, contentLogger) {
|
|
80417
80432
|
console.log();
|
|
80418
80433
|
oe(import_picocolors43.default.bgCyan(import_picocolors43.default.white(" CK Content — Multi-Channel Content Engine ")));
|
|
@@ -80480,8 +80495,8 @@ async function showRepoSummary(cwd2) {
|
|
|
80480
80495
|
function detectBrandAssets(cwd2, contentLogger) {
|
|
80481
80496
|
const repos = discoverRepos2(cwd2);
|
|
80482
80497
|
for (const repo of repos) {
|
|
80483
|
-
const hasGuidelines = existsSync89(
|
|
80484
|
-
const hasStyles = existsSync89(
|
|
80498
|
+
const hasGuidelines = existsSync89(join173(repo.path, "docs", "brand-guidelines.md"));
|
|
80499
|
+
const hasStyles = existsSync89(join173(repo.path, "assets", "writing-styles"));
|
|
80485
80500
|
if (!hasGuidelines) {
|
|
80486
80501
|
f2.warning(`${repo.name}: No docs/brand-guidelines.md — content will use generic tone.`);
|
|
80487
80502
|
contentLogger.warn(`${repo.name}: missing docs/brand-guidelines.md`);
|
|
@@ -80623,9 +80638,9 @@ __export(exports_content_subcommands, {
|
|
|
80623
80638
|
});
|
|
80624
80639
|
import { existsSync as existsSync91, readFileSync as readFileSync25, unlinkSync as unlinkSync6 } from "node:fs";
|
|
80625
80640
|
import { homedir as homedir58 } from "node:os";
|
|
80626
|
-
import { join as
|
|
80641
|
+
import { join as join174 } from "node:path";
|
|
80627
80642
|
function isDaemonRunning() {
|
|
80628
|
-
const lockFile =
|
|
80643
|
+
const lockFile = join174(LOCK_DIR, `${LOCK_NAME2}.lock`);
|
|
80629
80644
|
if (!existsSync91(lockFile))
|
|
80630
80645
|
return { running: false, pid: null };
|
|
80631
80646
|
try {
|
|
@@ -80657,7 +80672,7 @@ async function startContent(options2) {
|
|
|
80657
80672
|
await contentCommand(options2);
|
|
80658
80673
|
}
|
|
80659
80674
|
async function stopContent() {
|
|
80660
|
-
const lockFile =
|
|
80675
|
+
const lockFile = join174(LOCK_DIR, `${LOCK_NAME2}.lock`);
|
|
80661
80676
|
if (!existsSync91(lockFile)) {
|
|
80662
80677
|
logger.info("Content daemon is not running.");
|
|
80663
80678
|
return;
|
|
@@ -80696,9 +80711,9 @@ async function statusContent() {
|
|
|
80696
80711
|
} catch {}
|
|
80697
80712
|
}
|
|
80698
80713
|
async function logsContent(options2) {
|
|
80699
|
-
const logDir =
|
|
80714
|
+
const logDir = join174(homedir58(), ".claudekit", "logs");
|
|
80700
80715
|
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
80701
|
-
const logPath =
|
|
80716
|
+
const logPath = join174(logDir, `content-${dateStr}.log`);
|
|
80702
80717
|
if (!existsSync91(logPath)) {
|
|
80703
80718
|
logger.info("No content logs found for today.");
|
|
80704
80719
|
return;
|
|
@@ -80730,13 +80745,13 @@ var init_content_subcommands = __esm(() => {
|
|
|
80730
80745
|
init_setup_wizard();
|
|
80731
80746
|
init_state_manager();
|
|
80732
80747
|
init_content_review_commands();
|
|
80733
|
-
LOCK_DIR =
|
|
80748
|
+
LOCK_DIR = join174(homedir58(), ".claudekit", "locks");
|
|
80734
80749
|
});
|
|
80735
80750
|
|
|
80736
80751
|
// src/commands/content/content-command.ts
|
|
80737
80752
|
import { existsSync as existsSync92, mkdirSync as mkdirSync11, unlinkSync as unlinkSync7, writeFileSync as writeFileSync9 } from "node:fs";
|
|
80738
80753
|
import { homedir as homedir59 } from "node:os";
|
|
80739
|
-
import { join as
|
|
80754
|
+
import { join as join175 } from "node:path";
|
|
80740
80755
|
async function contentCommand(options2) {
|
|
80741
80756
|
const cwd2 = process.cwd();
|
|
80742
80757
|
const contentLogger = new ContentLogger;
|
|
@@ -80914,8 +80929,8 @@ var init_content_command = __esm(() => {
|
|
|
80914
80929
|
init_publisher();
|
|
80915
80930
|
init_review_manager();
|
|
80916
80931
|
init_state_manager();
|
|
80917
|
-
LOCK_DIR2 =
|
|
80918
|
-
LOCK_FILE =
|
|
80932
|
+
LOCK_DIR2 = join175(homedir59(), ".claudekit", "locks");
|
|
80933
|
+
LOCK_FILE = join175(LOCK_DIR2, "ck-content.lock");
|
|
80919
80934
|
});
|
|
80920
80935
|
|
|
80921
80936
|
// src/commands/content/index.ts
|
|
@@ -102749,7 +102764,7 @@ import { join as join122 } from "node:path";
|
|
|
102749
102764
|
|
|
102750
102765
|
// src/domains/installation/deletion-handler.ts
|
|
102751
102766
|
import { existsSync as existsSync66, lstatSync as lstatSync3, readdirSync as readdirSync10, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync4 } from "node:fs";
|
|
102752
|
-
import { dirname as dirname38, join as join107, relative as relative21, resolve as resolve42, sep as
|
|
102767
|
+
import { dirname as dirname38, join as join107, relative as relative21, resolve as resolve42, sep as sep12 } from "node:path";
|
|
102753
102768
|
|
|
102754
102769
|
// src/services/file-operations/manifest/manifest-reader.ts
|
|
102755
102770
|
init_metadata_migration();
|
|
@@ -102996,7 +103011,7 @@ function cleanupEmptyDirectories(filePath, claudeDir3) {
|
|
|
102996
103011
|
function deletePath(fullPath, claudeDir3) {
|
|
102997
103012
|
const normalizedPath = resolve42(fullPath);
|
|
102998
103013
|
const normalizedClaudeDir = resolve42(claudeDir3);
|
|
102999
|
-
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${
|
|
103014
|
+
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep12}`) && normalizedPath !== normalizedClaudeDir) {
|
|
103000
103015
|
throw new Error(`Path traversal detected: ${fullPath}`);
|
|
103001
103016
|
}
|
|
103002
103017
|
try {
|
|
@@ -103070,7 +103085,7 @@ async function handleDeletions(sourceMetadata, claudeDir3, kitType) {
|
|
|
103070
103085
|
const fullPath = join107(claudeDir3, path16);
|
|
103071
103086
|
const normalizedPath = resolve42(fullPath);
|
|
103072
103087
|
const normalizedClaudeDir = resolve42(claudeDir3);
|
|
103073
|
-
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${
|
|
103088
|
+
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep12}`)) {
|
|
103074
103089
|
logger.warning(`Skipping invalid path: ${path16}`);
|
|
103075
103090
|
result.errors.push(path16);
|
|
103076
103091
|
continue;
|
|
@@ -104168,8 +104183,8 @@ var path16 = {
|
|
|
104168
104183
|
win32: { sep: "\\" },
|
|
104169
104184
|
posix: { sep: "/" }
|
|
104170
104185
|
};
|
|
104171
|
-
var
|
|
104172
|
-
minimatch.sep =
|
|
104186
|
+
var sep13 = defaultPlatform === "win32" ? path16.win32.sep : path16.posix.sep;
|
|
104187
|
+
minimatch.sep = sep13;
|
|
104173
104188
|
var GLOBSTAR = Symbol("globstar **");
|
|
104174
104189
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
104175
104190
|
var qmark2 = "[^/]";
|
|
@@ -109497,6 +109512,9 @@ async function runPreflightChecks() {
|
|
|
109497
109512
|
return result;
|
|
109498
109513
|
}
|
|
109499
109514
|
|
|
109515
|
+
// src/commands/init/phases/selection-handler.ts
|
|
109516
|
+
init_hook_health_checker();
|
|
109517
|
+
|
|
109500
109518
|
// src/domains/installation/fresh-installer.ts
|
|
109501
109519
|
init_metadata_migration();
|
|
109502
109520
|
import { existsSync as existsSync70, readdirSync as readdirSync11, rmSync as rmSync5, rmdirSync as rmdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
|
|
@@ -110242,8 +110260,13 @@ async function handleSelection(ctx) {
|
|
|
110242
110260
|
const existingMetadata = await readManifest(claudeDir3);
|
|
110243
110261
|
const installedKitVersion = existingMetadata?.kits?.[kitType]?.version;
|
|
110244
110262
|
if (installedKitVersion && versionsMatch(installedKitVersion, releaseTag)) {
|
|
110245
|
-
|
|
110246
|
-
|
|
110263
|
+
const missingHookFiles = await countMissingHookFileReferencesForClaudeDir(claudeDir3);
|
|
110264
|
+
if (missingHookFiles > 0) {
|
|
110265
|
+
logger.warning(`Detected ${missingHookFiles} registered hook(s) whose script is missing on disk; reinstalling to restore them`);
|
|
110266
|
+
} else {
|
|
110267
|
+
logger.success(`Already at latest version (${kitType}@${installedKitVersion}), skipping reinstall`);
|
|
110268
|
+
return { ...ctx, cancelled: true };
|
|
110269
|
+
}
|
|
110247
110270
|
}
|
|
110248
110271
|
} catch (error) {
|
|
110249
110272
|
logger.verbose(`Metadata read failed, proceeding with installation: ${error instanceof Error ? error.message : "unknown"}`);
|
|
@@ -115992,11 +116015,11 @@ async function detectInstallations() {
|
|
|
115992
116015
|
|
|
115993
116016
|
// src/commands/uninstall/removal-handler.ts
|
|
115994
116017
|
import { readdirSync as readdirSync13, rmSync as rmSync8 } from "node:fs";
|
|
115995
|
-
import { basename as basename33, join as
|
|
116018
|
+
import { basename as basename33, join as join158, resolve as resolve56, sep as sep14 } from "node:path";
|
|
115996
116019
|
init_logger();
|
|
115997
116020
|
init_safe_prompts();
|
|
115998
116021
|
init_safe_spinner();
|
|
115999
|
-
var
|
|
116022
|
+
var import_fs_extra44 = __toESM(require_lib(), 1);
|
|
116000
116023
|
|
|
116001
116024
|
// src/commands/uninstall/analysis-handler.ts
|
|
116002
116025
|
init_metadata_migration();
|
|
@@ -116148,10 +116171,170 @@ function displayDryRunPreview(analysis, installationType) {
|
|
|
116148
116171
|
}
|
|
116149
116172
|
}
|
|
116150
116173
|
|
|
116174
|
+
// src/commands/uninstall/settings-cleanup.ts
|
|
116175
|
+
init_settings_merger();
|
|
116176
|
+
init_command_normalizer();
|
|
116177
|
+
init_logger();
|
|
116178
|
+
var import_fs_extra43 = __toESM(require_lib(), 1);
|
|
116179
|
+
import { join as join157 } from "node:path";
|
|
116180
|
+
var CK_JSON_FILE2 = ".ck.json";
|
|
116181
|
+
var SETTINGS_FILE = "settings.json";
|
|
116182
|
+
var EMPTY_RESULT = {
|
|
116183
|
+
hooksRemoved: 0,
|
|
116184
|
+
mcpServersRemoved: 0,
|
|
116185
|
+
settingsFileRemoved: false,
|
|
116186
|
+
ckJsonRemoved: false
|
|
116187
|
+
};
|
|
116188
|
+
function resolveRemovalTargets(kits, removedKitNames, remainingKits) {
|
|
116189
|
+
const retainedHooks = new Set;
|
|
116190
|
+
const retainedServers = new Set;
|
|
116191
|
+
for (const remainingKit of remainingKits) {
|
|
116192
|
+
const installed = kits[remainingKit]?.installedSettings;
|
|
116193
|
+
for (const command of installed?.hooks ?? []) {
|
|
116194
|
+
const normalized = normalizeCommand(command);
|
|
116195
|
+
if (normalized)
|
|
116196
|
+
retainedHooks.add(normalized);
|
|
116197
|
+
}
|
|
116198
|
+
for (const server of installed?.mcpServers ?? []) {
|
|
116199
|
+
retainedServers.add(server);
|
|
116200
|
+
}
|
|
116201
|
+
}
|
|
116202
|
+
const hooks = new Set;
|
|
116203
|
+
const servers = new Set;
|
|
116204
|
+
for (const kitName of removedKitNames) {
|
|
116205
|
+
const installed = kits[kitName]?.installedSettings;
|
|
116206
|
+
for (const command of installed?.hooks ?? []) {
|
|
116207
|
+
const normalized = normalizeCommand(command);
|
|
116208
|
+
if (normalized && !retainedHooks.has(normalized))
|
|
116209
|
+
hooks.add(normalized);
|
|
116210
|
+
}
|
|
116211
|
+
for (const server of installed?.mcpServers ?? []) {
|
|
116212
|
+
if (!retainedServers.has(server))
|
|
116213
|
+
servers.add(server);
|
|
116214
|
+
}
|
|
116215
|
+
}
|
|
116216
|
+
return { hooks, servers };
|
|
116217
|
+
}
|
|
116218
|
+
function removeHooksFromSettings(settings, normalizedToRemove) {
|
|
116219
|
+
if (!settings.hooks || normalizedToRemove.size === 0)
|
|
116220
|
+
return 0;
|
|
116221
|
+
let removed = 0;
|
|
116222
|
+
const eventKeysToDelete = [];
|
|
116223
|
+
for (const [eventName, entries] of Object.entries(settings.hooks)) {
|
|
116224
|
+
const keptEntries = [];
|
|
116225
|
+
for (const entry of entries) {
|
|
116226
|
+
if (Array.isArray(entry.hooks)) {
|
|
116227
|
+
const keptHooks = entry.hooks.filter((hook) => {
|
|
116228
|
+
if (typeof hook.command === "string" && normalizedToRemove.has(normalizeCommand(hook.command))) {
|
|
116229
|
+
removed++;
|
|
116230
|
+
return false;
|
|
116231
|
+
}
|
|
116232
|
+
return true;
|
|
116233
|
+
});
|
|
116234
|
+
if (keptHooks.length > 0) {
|
|
116235
|
+
keptEntries.push({ ...entry, hooks: keptHooks });
|
|
116236
|
+
}
|
|
116237
|
+
continue;
|
|
116238
|
+
}
|
|
116239
|
+
if (typeof entry.command === "string" && normalizedToRemove.has(normalizeCommand(entry.command))) {
|
|
116240
|
+
removed++;
|
|
116241
|
+
continue;
|
|
116242
|
+
}
|
|
116243
|
+
keptEntries.push(entry);
|
|
116244
|
+
}
|
|
116245
|
+
if (keptEntries.length > 0) {
|
|
116246
|
+
settings.hooks[eventName] = keptEntries;
|
|
116247
|
+
} else {
|
|
116248
|
+
eventKeysToDelete.push(eventName);
|
|
116249
|
+
}
|
|
116250
|
+
}
|
|
116251
|
+
for (const eventName of eventKeysToDelete) {
|
|
116252
|
+
delete settings.hooks[eventName];
|
|
116253
|
+
}
|
|
116254
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
116255
|
+
Reflect.deleteProperty(settings, "hooks");
|
|
116256
|
+
}
|
|
116257
|
+
return removed;
|
|
116258
|
+
}
|
|
116259
|
+
function removeMcpServersFromSettings(settings, serversToRemove) {
|
|
116260
|
+
const servers = settings.mcp?.servers;
|
|
116261
|
+
if (!servers || serversToRemove.size === 0)
|
|
116262
|
+
return 0;
|
|
116263
|
+
let removed = 0;
|
|
116264
|
+
for (const name2 of serversToRemove) {
|
|
116265
|
+
if (Object.hasOwn(servers, name2)) {
|
|
116266
|
+
delete servers[name2];
|
|
116267
|
+
removed++;
|
|
116268
|
+
}
|
|
116269
|
+
}
|
|
116270
|
+
if (removed > 0 && settings.mcp) {
|
|
116271
|
+
if (Object.keys(servers).length === 0) {
|
|
116272
|
+
Reflect.deleteProperty(settings.mcp, "servers");
|
|
116273
|
+
}
|
|
116274
|
+
if (Object.keys(settings.mcp).length === 0) {
|
|
116275
|
+
Reflect.deleteProperty(settings, "mcp");
|
|
116276
|
+
}
|
|
116277
|
+
}
|
|
116278
|
+
return removed;
|
|
116279
|
+
}
|
|
116280
|
+
async function cleanupCkJson(ckJsonPath, data, removedKitNames, dryRun) {
|
|
116281
|
+
if (!data.kits)
|
|
116282
|
+
return false;
|
|
116283
|
+
for (const kitName of removedKitNames) {
|
|
116284
|
+
delete data.kits[kitName];
|
|
116285
|
+
}
|
|
116286
|
+
const noKitsLeft = Object.keys(data.kits).length === 0;
|
|
116287
|
+
const otherTopLevelKeys = Object.keys(data).filter((key) => key !== "kits");
|
|
116288
|
+
if (dryRun)
|
|
116289
|
+
return noKitsLeft && otherTopLevelKeys.length === 0;
|
|
116290
|
+
if (noKitsLeft && otherTopLevelKeys.length === 0) {
|
|
116291
|
+
await import_fs_extra43.remove(ckJsonPath);
|
|
116292
|
+
return true;
|
|
116293
|
+
}
|
|
116294
|
+
if (noKitsLeft) {
|
|
116295
|
+
Reflect.deleteProperty(data, "kits");
|
|
116296
|
+
}
|
|
116297
|
+
await import_fs_extra43.writeFile(ckJsonPath, JSON.stringify(data, null, 2), "utf-8");
|
|
116298
|
+
return false;
|
|
116299
|
+
}
|
|
116300
|
+
async function cleanupUninstalledSettings(installationPath, options2) {
|
|
116301
|
+
const ckJsonPath = join157(installationPath, CK_JSON_FILE2);
|
|
116302
|
+
if (!await import_fs_extra43.pathExists(ckJsonPath)) {
|
|
116303
|
+
return { ...EMPTY_RESULT };
|
|
116304
|
+
}
|
|
116305
|
+
let data;
|
|
116306
|
+
try {
|
|
116307
|
+
data = parseJsonContent(await import_fs_extra43.readFile(ckJsonPath, "utf-8"));
|
|
116308
|
+
} catch (error) {
|
|
116309
|
+
logger.debug(`Settings cleanup: failed to parse ${ckJsonPath}: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
116310
|
+
return { ...EMPTY_RESULT };
|
|
116311
|
+
}
|
|
116312
|
+
const kits = data.kits ?? {};
|
|
116313
|
+
const removedKitNames = options2.kit ? [options2.kit] : Object.keys(kits);
|
|
116314
|
+
const { hooks, servers } = resolveRemovalTargets(kits, removedKitNames, options2.remainingKits);
|
|
116315
|
+
const result = { ...EMPTY_RESULT };
|
|
116316
|
+
const settingsPath = join157(installationPath, SETTINGS_FILE);
|
|
116317
|
+
const settings = await SettingsMerger.readSettingsFile(settingsPath);
|
|
116318
|
+
if (settings) {
|
|
116319
|
+
result.hooksRemoved = removeHooksFromSettings(settings, hooks);
|
|
116320
|
+
result.mcpServersRemoved = removeMcpServersFromSettings(settings, servers);
|
|
116321
|
+
if (!options2.dryRun && (result.hooksRemoved > 0 || result.mcpServersRemoved > 0)) {
|
|
116322
|
+
if (Object.keys(settings).length === 0) {
|
|
116323
|
+
await import_fs_extra43.remove(settingsPath);
|
|
116324
|
+
result.settingsFileRemoved = true;
|
|
116325
|
+
} else {
|
|
116326
|
+
await SettingsMerger.writeSettingsFile(settingsPath, settings);
|
|
116327
|
+
}
|
|
116328
|
+
}
|
|
116329
|
+
}
|
|
116330
|
+
result.ckJsonRemoved = await cleanupCkJson(ckJsonPath, data, removedKitNames, options2.dryRun ?? false);
|
|
116331
|
+
return result;
|
|
116332
|
+
}
|
|
116333
|
+
|
|
116151
116334
|
// src/commands/uninstall/removal-handler.ts
|
|
116152
116335
|
async function isDirectory2(filePath) {
|
|
116153
116336
|
try {
|
|
116154
|
-
const stats = await
|
|
116337
|
+
const stats = await import_fs_extra44.lstat(filePath);
|
|
116155
116338
|
return stats.isDirectory();
|
|
116156
116339
|
} catch {
|
|
116157
116340
|
logger.debug(`Failed to check if path is directory: ${filePath}`);
|
|
@@ -116159,10 +116342,30 @@ async function isDirectory2(filePath) {
|
|
|
116159
116342
|
}
|
|
116160
116343
|
}
|
|
116161
116344
|
function getUninstallMutatePaths(options2) {
|
|
116345
|
+
const paths = [];
|
|
116162
116346
|
if (options2.retainedManifestPaths.length > 0) {
|
|
116163
|
-
|
|
116347
|
+
paths.push("metadata.json");
|
|
116164
116348
|
}
|
|
116165
|
-
|
|
116349
|
+
if (options2.settingsFileExists) {
|
|
116350
|
+
paths.push("settings.json");
|
|
116351
|
+
}
|
|
116352
|
+
if (options2.ckJsonExists) {
|
|
116353
|
+
paths.push(".ck.json");
|
|
116354
|
+
}
|
|
116355
|
+
return paths;
|
|
116356
|
+
}
|
|
116357
|
+
function logSettingsCleanup(result, dryRun) {
|
|
116358
|
+
if (result.hooksRemoved === 0 && result.mcpServersRemoved === 0)
|
|
116359
|
+
return;
|
|
116360
|
+
const parts = [];
|
|
116361
|
+
if (result.hooksRemoved > 0) {
|
|
116362
|
+
parts.push(`${result.hooksRemoved} hook${result.hooksRemoved === 1 ? "" : "s"}`);
|
|
116363
|
+
}
|
|
116364
|
+
if (result.mcpServersRemoved > 0) {
|
|
116365
|
+
parts.push(`${result.mcpServersRemoved} MCP server${result.mcpServersRemoved === 1 ? "" : "s"}`);
|
|
116366
|
+
}
|
|
116367
|
+
const verb = dryRun ? "Would remove" : "Removed";
|
|
116368
|
+
log.info(`${verb} ${parts.join(" and ")} from settings.json`);
|
|
116166
116369
|
}
|
|
116167
116370
|
async function restoreUninstallBackup(backup) {
|
|
116168
116371
|
const restoreSpinner = createSpinner("Restoring installation from recovery backup...").start();
|
|
@@ -116178,15 +116381,15 @@ async function isPathSafeToRemove(filePath, baseDir) {
|
|
|
116178
116381
|
try {
|
|
116179
116382
|
const resolvedPath = resolve56(filePath);
|
|
116180
116383
|
const resolvedBase = resolve56(baseDir);
|
|
116181
|
-
if (!resolvedPath.startsWith(resolvedBase +
|
|
116384
|
+
if (!resolvedPath.startsWith(resolvedBase + sep14) && resolvedPath !== resolvedBase) {
|
|
116182
116385
|
logger.debug(`Path outside installation directory: ${filePath}`);
|
|
116183
116386
|
return false;
|
|
116184
116387
|
}
|
|
116185
|
-
const stats = await
|
|
116388
|
+
const stats = await import_fs_extra44.lstat(filePath);
|
|
116186
116389
|
if (stats.isSymbolicLink()) {
|
|
116187
|
-
const realPath = await
|
|
116390
|
+
const realPath = await import_fs_extra44.realpath(filePath);
|
|
116188
116391
|
const resolvedReal = resolve56(realPath);
|
|
116189
|
-
if (!resolvedReal.startsWith(resolvedBase +
|
|
116392
|
+
if (!resolvedReal.startsWith(resolvedBase + sep14) && resolvedReal !== resolvedBase) {
|
|
116190
116393
|
logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
|
|
116191
116394
|
return false;
|
|
116192
116395
|
}
|
|
@@ -116208,6 +116411,12 @@ async function removeInstallations(installations, options2) {
|
|
|
116208
116411
|
const label = options2.kit ? `${installation.type} (${options2.kit} kit)` : installation.type;
|
|
116209
116412
|
const legacyLabel2 = !installation.hasMetadata ? " [legacy]" : "";
|
|
116210
116413
|
displayDryRunPreview(analysis, `${label}${legacyLabel2}`);
|
|
116414
|
+
const settingsPreview = await cleanupUninstalledSettings(installation.path, {
|
|
116415
|
+
kit: options2.kit,
|
|
116416
|
+
remainingKits: analysis.remainingKits,
|
|
116417
|
+
dryRun: true
|
|
116418
|
+
});
|
|
116419
|
+
logSettingsCleanup(settingsPreview, true);
|
|
116211
116420
|
if (analysis.remainingKits.length > 0) {
|
|
116212
116421
|
log.info(`Remaining kits after uninstall: ${analysis.remainingKits.join(", ")}`);
|
|
116213
116422
|
}
|
|
@@ -116217,7 +116426,9 @@ async function removeInstallations(installations, options2) {
|
|
|
116217
116426
|
continue;
|
|
116218
116427
|
}
|
|
116219
116428
|
const mutatePaths = getUninstallMutatePaths({
|
|
116220
|
-
retainedManifestPaths: analysis.retainedManifestPaths
|
|
116429
|
+
retainedManifestPaths: analysis.retainedManifestPaths,
|
|
116430
|
+
settingsFileExists: await import_fs_extra44.pathExists(join158(installation.path, "settings.json")),
|
|
116431
|
+
ckJsonExists: await import_fs_extra44.pathExists(join158(installation.path, ".ck.json"))
|
|
116221
116432
|
});
|
|
116222
116433
|
let backup = null;
|
|
116223
116434
|
if (analysis.toDelete.length > 0 || mutatePaths.length > 0) {
|
|
@@ -116245,15 +116456,15 @@ async function removeInstallations(installations, options2) {
|
|
|
116245
116456
|
let removedCount = 0;
|
|
116246
116457
|
let cleanedDirs = 0;
|
|
116247
116458
|
for (const item of analysis.toDelete) {
|
|
116248
|
-
const filePath =
|
|
116249
|
-
if (!await
|
|
116459
|
+
const filePath = join158(installation.path, item.path);
|
|
116460
|
+
if (!await import_fs_extra44.pathExists(filePath))
|
|
116250
116461
|
continue;
|
|
116251
116462
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
116252
116463
|
logger.debug(`Skipping unsafe path: ${item.path}`);
|
|
116253
116464
|
continue;
|
|
116254
116465
|
}
|
|
116255
116466
|
const isDir2 = await isDirectory2(filePath);
|
|
116256
|
-
await
|
|
116467
|
+
await import_fs_extra44.remove(filePath);
|
|
116257
116468
|
removedCount++;
|
|
116258
116469
|
logger.debug(`Removed ${isDir2 ? "directory" : "file"}: ${item.path}`);
|
|
116259
116470
|
if (!isDir2) {
|
|
@@ -116269,6 +116480,11 @@ async function removeInstallations(installations, options2) {
|
|
|
116269
116480
|
throw new Error("Failed to update metadata.json after partial uninstall");
|
|
116270
116481
|
}
|
|
116271
116482
|
}
|
|
116483
|
+
const settingsCleanup = await cleanupUninstalledSettings(installation.path, {
|
|
116484
|
+
kit: options2.kit,
|
|
116485
|
+
remainingKits: analysis.remainingKits
|
|
116486
|
+
});
|
|
116487
|
+
logSettingsCleanup(settingsCleanup, false);
|
|
116272
116488
|
try {
|
|
116273
116489
|
const remaining = readdirSync13(installation.path);
|
|
116274
116490
|
if (remaining.length === 0) {
|
|
@@ -116667,7 +116883,7 @@ ${import_picocolors40.default.bold(import_picocolors40.default.cyan(result.kitCo
|
|
|
116667
116883
|
init_logger();
|
|
116668
116884
|
import { existsSync as existsSync82 } from "node:fs";
|
|
116669
116885
|
import { rm as rm19 } from "node:fs/promises";
|
|
116670
|
-
import { join as
|
|
116886
|
+
import { join as join165 } from "node:path";
|
|
116671
116887
|
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
116672
116888
|
|
|
116673
116889
|
// src/commands/watch/phases/implementation-runner.ts
|
|
@@ -117185,8 +117401,8 @@ function spawnAndCollect3(command, args) {
|
|
|
117185
117401
|
}
|
|
117186
117402
|
|
|
117187
117403
|
// src/commands/watch/phases/issue-processor.ts
|
|
117188
|
-
import { mkdir as mkdir40, writeFile as
|
|
117189
|
-
import { join as
|
|
117404
|
+
import { mkdir as mkdir40, writeFile as writeFile42 } from "node:fs/promises";
|
|
117405
|
+
import { join as join161 } from "node:path";
|
|
117190
117406
|
|
|
117191
117407
|
// src/commands/watch/phases/approval-detector.ts
|
|
117192
117408
|
init_logger();
|
|
@@ -117564,9 +117780,9 @@ async function checkAwaitingApproval(state, setup, options2, watchLog, projectDi
|
|
|
117564
117780
|
|
|
117565
117781
|
// src/commands/watch/phases/plan-dir-finder.ts
|
|
117566
117782
|
import { readdir as readdir46, stat as stat24 } from "node:fs/promises";
|
|
117567
|
-
import { join as
|
|
117783
|
+
import { join as join160 } from "node:path";
|
|
117568
117784
|
async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
|
|
117569
|
-
const plansRoot =
|
|
117785
|
+
const plansRoot = join160(cwd2, "plans");
|
|
117570
117786
|
try {
|
|
117571
117787
|
const entries = await readdir46(plansRoot);
|
|
117572
117788
|
const tenMinAgo = Date.now() - 10 * 60 * 1000;
|
|
@@ -117575,14 +117791,14 @@ async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
|
|
|
117575
117791
|
for (const entry of entries) {
|
|
117576
117792
|
if (entry === "watch" || entry === "reports" || entry === "visuals")
|
|
117577
117793
|
continue;
|
|
117578
|
-
const dirPath =
|
|
117794
|
+
const dirPath = join160(plansRoot, entry);
|
|
117579
117795
|
const dirStat = await stat24(dirPath);
|
|
117580
117796
|
if (!dirStat.isDirectory())
|
|
117581
117797
|
continue;
|
|
117582
117798
|
if (dirStat.mtimeMs < tenMinAgo)
|
|
117583
117799
|
continue;
|
|
117584
117800
|
try {
|
|
117585
|
-
await stat24(
|
|
117801
|
+
await stat24(join160(dirPath, "plan.md"));
|
|
117586
117802
|
} catch {
|
|
117587
117803
|
continue;
|
|
117588
117804
|
}
|
|
@@ -117813,14 +118029,14 @@ async function handlePlanGeneration(issue, state, config, setup, options2, watch
|
|
|
117813
118029
|
stats.plansCreated++;
|
|
117814
118030
|
const detectedPlanDir = await findRecentPlanDir(projectDir, issue.number, watchLog);
|
|
117815
118031
|
if (detectedPlanDir) {
|
|
117816
|
-
state.activeIssues[numStr].planPath =
|
|
118032
|
+
state.activeIssues[numStr].planPath = join161(detectedPlanDir, "plan.md");
|
|
117817
118033
|
watchLog.info(`Plan directory detected: ${detectedPlanDir}`);
|
|
117818
118034
|
} else {
|
|
117819
118035
|
try {
|
|
117820
|
-
const planDir =
|
|
118036
|
+
const planDir = join161(projectDir, "plans", "watch");
|
|
117821
118037
|
await mkdir40(planDir, { recursive: true });
|
|
117822
|
-
const planFilePath =
|
|
117823
|
-
await
|
|
118038
|
+
const planFilePath = join161(planDir, `issue-${issue.number}-plan.md`);
|
|
118039
|
+
await writeFile42(planFilePath, planResult.planText, "utf-8");
|
|
117824
118040
|
state.activeIssues[numStr].planPath = planFilePath;
|
|
117825
118041
|
watchLog.info(`Plan saved (fallback) to ${planFilePath}`);
|
|
117826
118042
|
} catch (err) {
|
|
@@ -117965,7 +118181,7 @@ init_ck_config_manager();
|
|
|
117965
118181
|
init_file_io();
|
|
117966
118182
|
init_logger();
|
|
117967
118183
|
import { existsSync as existsSync78 } from "node:fs";
|
|
117968
|
-
import { mkdir as mkdir41, readFile as
|
|
118184
|
+
import { mkdir as mkdir41, readFile as readFile71 } from "node:fs/promises";
|
|
117969
118185
|
import { dirname as dirname54 } from "node:path";
|
|
117970
118186
|
var PROCESSED_ISSUES_CAP = 500;
|
|
117971
118187
|
async function readCkJson(projectDir) {
|
|
@@ -117973,7 +118189,7 @@ async function readCkJson(projectDir) {
|
|
|
117973
118189
|
try {
|
|
117974
118190
|
if (!existsSync78(configPath))
|
|
117975
118191
|
return {};
|
|
117976
|
-
const content = await
|
|
118192
|
+
const content = await readFile71(configPath, "utf-8");
|
|
117977
118193
|
return JSON.parse(content);
|
|
117978
118194
|
} catch (error) {
|
|
117979
118195
|
logger.warning(`Failed to parse .ck.json: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
@@ -118126,18 +118342,18 @@ init_logger();
|
|
|
118126
118342
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
118127
118343
|
import { existsSync as existsSync79 } from "node:fs";
|
|
118128
118344
|
import { readdir as readdir47, stat as stat25 } from "node:fs/promises";
|
|
118129
|
-
import { join as
|
|
118345
|
+
import { join as join162 } from "node:path";
|
|
118130
118346
|
async function scanForRepos(parentDir) {
|
|
118131
118347
|
const repos = [];
|
|
118132
118348
|
const entries = await readdir47(parentDir);
|
|
118133
118349
|
for (const entry of entries) {
|
|
118134
118350
|
if (entry.startsWith("."))
|
|
118135
118351
|
continue;
|
|
118136
|
-
const fullPath =
|
|
118352
|
+
const fullPath = join162(parentDir, entry);
|
|
118137
118353
|
const entryStat = await stat25(fullPath);
|
|
118138
118354
|
if (!entryStat.isDirectory())
|
|
118139
118355
|
continue;
|
|
118140
|
-
const gitDir =
|
|
118356
|
+
const gitDir = join162(fullPath, ".git");
|
|
118141
118357
|
if (!existsSync79(gitDir))
|
|
118142
118358
|
continue;
|
|
118143
118359
|
const result = spawnSync7("gh", ["repo", "view", "--json", "owner,name"], {
|
|
@@ -118164,7 +118380,7 @@ init_logger();
|
|
|
118164
118380
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
118165
118381
|
import { existsSync as existsSync80 } from "node:fs";
|
|
118166
118382
|
import { homedir as homedir53 } from "node:os";
|
|
118167
|
-
import { join as
|
|
118383
|
+
import { join as join163 } from "node:path";
|
|
118168
118384
|
async function validateSetup(cwd2) {
|
|
118169
118385
|
const workDir = cwd2 ?? process.cwd();
|
|
118170
118386
|
const ghVersion = spawnSync8("gh", ["--version"], { encoding: "utf-8", timeout: 1e4 });
|
|
@@ -118195,7 +118411,7 @@ Run this command from a directory with a GitHub remote.`);
|
|
|
118195
118411
|
} catch {
|
|
118196
118412
|
throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
|
|
118197
118413
|
}
|
|
118198
|
-
const skillsPath =
|
|
118414
|
+
const skillsPath = join163(homedir53(), ".claude", "skills");
|
|
118199
118415
|
const skillsAvailable = existsSync80(skillsPath);
|
|
118200
118416
|
if (!skillsAvailable) {
|
|
118201
118417
|
logger.warning(`ClaudeKit Engineer skills not found at ${skillsPath}`);
|
|
@@ -118214,7 +118430,7 @@ init_path_resolver();
|
|
|
118214
118430
|
import { createWriteStream as createWriteStream3, statSync as statSync14 } from "node:fs";
|
|
118215
118431
|
import { existsSync as existsSync81 } from "node:fs";
|
|
118216
118432
|
import { mkdir as mkdir42, rename as rename15 } from "node:fs/promises";
|
|
118217
|
-
import { join as
|
|
118433
|
+
import { join as join164 } from "node:path";
|
|
118218
118434
|
|
|
118219
118435
|
class WatchLogger {
|
|
118220
118436
|
logStream = null;
|
|
@@ -118222,7 +118438,7 @@ class WatchLogger {
|
|
|
118222
118438
|
logPath = null;
|
|
118223
118439
|
maxBytes;
|
|
118224
118440
|
constructor(logDir, maxBytes = 0) {
|
|
118225
|
-
this.logDir = logDir ??
|
|
118441
|
+
this.logDir = logDir ?? join164(PathResolver.getClaudeKitDir(), "logs");
|
|
118226
118442
|
this.maxBytes = maxBytes;
|
|
118227
118443
|
}
|
|
118228
118444
|
async init() {
|
|
@@ -118231,7 +118447,7 @@ class WatchLogger {
|
|
|
118231
118447
|
await mkdir42(this.logDir, { recursive: true });
|
|
118232
118448
|
}
|
|
118233
118449
|
const dateStr = formatDate(new Date);
|
|
118234
|
-
this.logPath =
|
|
118450
|
+
this.logPath = join164(this.logDir, `watch-${dateStr}.log`);
|
|
118235
118451
|
this.logStream = createWriteStream3(this.logPath, { flags: "a", mode: 384 });
|
|
118236
118452
|
} catch (error) {
|
|
118237
118453
|
logger.warning(`Cannot create watch log file: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
@@ -118413,7 +118629,7 @@ async function watchCommand(options2) {
|
|
|
118413
118629
|
}
|
|
118414
118630
|
async function discoverRepos(options2, watchLog) {
|
|
118415
118631
|
const cwd2 = process.cwd();
|
|
118416
|
-
const isGitRepo = existsSync82(
|
|
118632
|
+
const isGitRepo = existsSync82(join165(cwd2, ".git"));
|
|
118417
118633
|
if (options2.force) {
|
|
118418
118634
|
await forceRemoveLock(watchLog);
|
|
118419
118635
|
}
|
|
@@ -118671,7 +118887,7 @@ function registerCommands(cli) {
|
|
|
118671
118887
|
init_package();
|
|
118672
118888
|
init_config_version_checker();
|
|
118673
118889
|
import { existsSync as existsSync94, readFileSync as readFileSync26 } from "node:fs";
|
|
118674
|
-
import { join as
|
|
118890
|
+
import { join as join177 } from "node:path";
|
|
118675
118891
|
|
|
118676
118892
|
// src/domains/versioning/version-checker.ts
|
|
118677
118893
|
init_version_utils();
|
|
@@ -118685,15 +118901,15 @@ init_types3();
|
|
|
118685
118901
|
init_logger();
|
|
118686
118902
|
init_path_resolver();
|
|
118687
118903
|
import { existsSync as existsSync93 } from "node:fs";
|
|
118688
|
-
import { mkdir as mkdir43, readFile as
|
|
118689
|
-
import { join as
|
|
118904
|
+
import { mkdir as mkdir43, readFile as readFile73, writeFile as writeFile45 } from "node:fs/promises";
|
|
118905
|
+
import { join as join176 } from "node:path";
|
|
118690
118906
|
|
|
118691
118907
|
class VersionCacheManager {
|
|
118692
118908
|
static CACHE_FILENAME = "version-check.json";
|
|
118693
118909
|
static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
118694
118910
|
static getCacheFile() {
|
|
118695
118911
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
118696
|
-
return
|
|
118912
|
+
return join176(cacheDir, VersionCacheManager.CACHE_FILENAME);
|
|
118697
118913
|
}
|
|
118698
118914
|
static async load() {
|
|
118699
118915
|
const cacheFile = VersionCacheManager.getCacheFile();
|
|
@@ -118702,7 +118918,7 @@ class VersionCacheManager {
|
|
|
118702
118918
|
logger.debug("Version check cache not found");
|
|
118703
118919
|
return null;
|
|
118704
118920
|
}
|
|
118705
|
-
const content = await
|
|
118921
|
+
const content = await readFile73(cacheFile, "utf-8");
|
|
118706
118922
|
const cache5 = JSON.parse(content);
|
|
118707
118923
|
if (!cache5.lastCheck || !cache5.currentVersion || !cache5.latestVersion) {
|
|
118708
118924
|
logger.debug("Invalid cache structure, ignoring");
|
|
@@ -118722,7 +118938,7 @@ class VersionCacheManager {
|
|
|
118722
118938
|
if (!existsSync93(cacheDir)) {
|
|
118723
118939
|
await mkdir43(cacheDir, { recursive: true, mode: 448 });
|
|
118724
118940
|
}
|
|
118725
|
-
await
|
|
118941
|
+
await writeFile45(cacheFile, JSON.stringify(cache5, null, 2), "utf-8");
|
|
118726
118942
|
logger.debug(`Version check cache saved to ${cacheFile}`);
|
|
118727
118943
|
} catch (error) {
|
|
118728
118944
|
logger.debug(`Failed to save version check cache: ${error}`);
|
|
@@ -119004,9 +119220,9 @@ async function displayVersion() {
|
|
|
119004
119220
|
let localInstalledKits = [];
|
|
119005
119221
|
let globalInstalledKits = [];
|
|
119006
119222
|
const globalKitDir = PathResolver.getGlobalKitDir();
|
|
119007
|
-
const globalMetadataPath =
|
|
119223
|
+
const globalMetadataPath = join177(globalKitDir, "metadata.json");
|
|
119008
119224
|
const prefix = PathResolver.getPathPrefix(false);
|
|
119009
|
-
const localMetadataPath = prefix ?
|
|
119225
|
+
const localMetadataPath = prefix ? join177(process.cwd(), prefix, "metadata.json") : join177(process.cwd(), "metadata.json");
|
|
119010
119226
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
119011
119227
|
if (!isLocalSameAsGlobal && existsSync94(localMetadataPath)) {
|
|
119012
119228
|
try {
|
|
@@ -119394,7 +119610,7 @@ var output2 = new OutputManager2;
|
|
|
119394
119610
|
|
|
119395
119611
|
// src/shared/temp-cleanup.ts
|
|
119396
119612
|
init_logger();
|
|
119397
|
-
var
|
|
119613
|
+
var import_fs_extra45 = __toESM(require_lib(), 1);
|
|
119398
119614
|
import { rmSync as rmSync9 } from "node:fs";
|
|
119399
119615
|
var tempDirs2 = new Set;
|
|
119400
119616
|
async function cleanup() {
|
|
@@ -119403,7 +119619,7 @@ async function cleanup() {
|
|
|
119403
119619
|
logger.debug(`Cleaning up ${tempDirs2.size} temporary director(ies)...`);
|
|
119404
119620
|
for (const dir of tempDirs2) {
|
|
119405
119621
|
try {
|
|
119406
|
-
await
|
|
119622
|
+
await import_fs_extra45.remove(dir);
|
|
119407
119623
|
logger.debug(`Cleaned up temp directory: ${dir}`);
|
|
119408
119624
|
} catch (error) {
|
|
119409
119625
|
logger.debug(`Failed to clean temp directory ${dir}: ${error}`);
|