claudekit-cli 4.3.1-dev.10 → 4.3.1-dev.12
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/bin/postinstall-self-heal.cjs +143 -0
- package/cli-manifest.json +2 -2
- package/dist/index.js +55 -24
- package/package.json +3 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const os = require("node:os");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
|
|
8
|
+
const MAX_SETTINGS_BYTES = 5 * 1024 * 1024;
|
|
9
|
+
|
|
10
|
+
function isLegacyDescriptiveNamePrompt(entry) {
|
|
11
|
+
if (!entry || entry.type !== "prompt" || typeof entry.prompt !== "string") return false;
|
|
12
|
+
|
|
13
|
+
const prompt = entry.prompt;
|
|
14
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
15
|
+
const isOriginalLegacyPrompt =
|
|
16
|
+
prompt.includes("Use kebab-case file naming") &&
|
|
17
|
+
prompt.includes("self-documenting") &&
|
|
18
|
+
prompt.includes("Grep, Glob, Search");
|
|
19
|
+
const isDescriptiveNameKebabPrompt =
|
|
20
|
+
lowerPrompt.includes("descriptive-name") &&
|
|
21
|
+
lowerPrompt.includes("kebab-case") &&
|
|
22
|
+
(lowerPrompt.includes("file") || lowerPrompt.includes("filename"));
|
|
23
|
+
|
|
24
|
+
return isOriginalLegacyPrompt || isDescriptiveNameKebabPrompt;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function pruneHooks(settings) {
|
|
28
|
+
if (!settings || typeof settings !== "object" || !settings.hooks) return 0;
|
|
29
|
+
|
|
30
|
+
let pruned = 0;
|
|
31
|
+
for (const [eventName, entries] of Object.entries(settings.hooks)) {
|
|
32
|
+
if (!Array.isArray(entries)) continue;
|
|
33
|
+
|
|
34
|
+
const keptEntries = [];
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
if (isLegacyDescriptiveNamePrompt(entry)) {
|
|
37
|
+
pruned++;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (Array.isArray(entry?.hooks)) {
|
|
42
|
+
const keptHooks = entry.hooks.filter((hook) => {
|
|
43
|
+
if (isLegacyDescriptiveNamePrompt(hook)) {
|
|
44
|
+
pruned++;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
});
|
|
49
|
+
if (keptHooks.length > 0) keptEntries.push({ ...entry, hooks: keptHooks });
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
keptEntries.push(entry);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (keptEntries.length === 0) {
|
|
57
|
+
delete settings.hooks[eventName];
|
|
58
|
+
} else {
|
|
59
|
+
settings.hooks[eventName] = keptEntries;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (Object.keys(settings.hooks).length === 0) settings.hooks = undefined;
|
|
64
|
+
return pruned;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function pruneSettingsFile(filePath) {
|
|
68
|
+
try {
|
|
69
|
+
if (!filePath || !fs.existsSync(filePath)) return 0;
|
|
70
|
+
const stat = fs.statSync(filePath);
|
|
71
|
+
if (!stat.isFile() || stat.size > MAX_SETTINGS_BYTES) return 0;
|
|
72
|
+
|
|
73
|
+
const settings = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
74
|
+
const pruned = pruneHooks(settings);
|
|
75
|
+
if (pruned > 0) {
|
|
76
|
+
fs.writeFileSync(filePath, `${JSON.stringify(settings, null, 2)}\n`);
|
|
77
|
+
}
|
|
78
|
+
return pruned;
|
|
79
|
+
} catch {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getHomeDir() {
|
|
85
|
+
return process.env.CK_TEST_HOME || os.homedir();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function addIfSettingsFile(files, filePath) {
|
|
89
|
+
if (!filePath) return;
|
|
90
|
+
const base = path.basename(filePath);
|
|
91
|
+
if (
|
|
92
|
+
base === "settings.json" ||
|
|
93
|
+
base === "settings.local.json" ||
|
|
94
|
+
base.endsWith(".settings.json")
|
|
95
|
+
) {
|
|
96
|
+
files.add(path.resolve(filePath));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function collectCandidateSettingsFiles() {
|
|
101
|
+
const files = new Set();
|
|
102
|
+
const initCwd = process.env.INIT_CWD;
|
|
103
|
+
if (initCwd && path.isAbsolute(initCwd)) {
|
|
104
|
+
addIfSettingsFile(files, path.join(initCwd, ".claude", "settings.json"));
|
|
105
|
+
addIfSettingsFile(files, path.join(initCwd, ".claude", "settings.local.json"));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const homeDir = getHomeDir();
|
|
109
|
+
const globalClaudeDir = process.env.CLAUDE_CONFIG_DIR || path.join(homeDir, ".claude");
|
|
110
|
+
addIfSettingsFile(files, path.join(globalClaudeDir, "settings.json"));
|
|
111
|
+
addIfSettingsFile(files, path.join(globalClaudeDir, "settings.local.json"));
|
|
112
|
+
|
|
113
|
+
const ccsDir = process.env.CK_TEST_CCS_DIR || path.join(homeDir, ".ccs");
|
|
114
|
+
try {
|
|
115
|
+
for (const dirent of fs.readdirSync(ccsDir, { withFileTypes: true })) {
|
|
116
|
+
if (dirent.isFile()) addIfSettingsFile(files, path.join(ccsDir, dirent.name));
|
|
117
|
+
}
|
|
118
|
+
} catch {
|
|
119
|
+
// Optional compatibility directory; skip when absent or unreadable.
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return [...files];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function main() {
|
|
126
|
+
let pruned = 0;
|
|
127
|
+
for (const filePath of collectCandidateSettingsFiles()) {
|
|
128
|
+
pruned += pruneSettingsFile(filePath);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (pruned > 0 && process.env.CK_POSTINSTALL_DEBUG === "1") {
|
|
132
|
+
console.warn(`[claudekit-cli] Pruned ${pruned} legacy hook prompt(s)`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
main();
|
|
137
|
+
|
|
138
|
+
module.exports = {
|
|
139
|
+
collectCandidateSettingsFiles,
|
|
140
|
+
isLegacyDescriptiveNamePrompt,
|
|
141
|
+
pruneHooks,
|
|
142
|
+
pruneSettingsFile,
|
|
143
|
+
};
|
package/cli-manifest.json
CHANGED
package/dist/index.js
CHANGED
|
@@ -63357,7 +63357,7 @@ var package_default;
|
|
|
63357
63357
|
var init_package = __esm(() => {
|
|
63358
63358
|
package_default = {
|
|
63359
63359
|
name: "claudekit-cli",
|
|
63360
|
-
version: "4.3.1-dev.
|
|
63360
|
+
version: "4.3.1-dev.12",
|
|
63361
63361
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
63362
63362
|
type: "module",
|
|
63363
63363
|
repository: {
|
|
@@ -63373,6 +63373,7 @@ var init_package = __esm(() => {
|
|
|
63373
63373
|
},
|
|
63374
63374
|
files: [
|
|
63375
63375
|
"bin/ck.js",
|
|
63376
|
+
"bin/postinstall-self-heal.cjs",
|
|
63376
63377
|
"dist/index.js",
|
|
63377
63378
|
"dist/ui/",
|
|
63378
63379
|
"cli-manifest.json"
|
|
@@ -63404,6 +63405,7 @@ var init_package = __esm(() => {
|
|
|
63404
63405
|
"ci:local": "bash scripts/ci-local.sh",
|
|
63405
63406
|
"install:hooks": "./.githooks/install.sh",
|
|
63406
63407
|
prepare: `node -e "try{require('child_process').execSync('git rev-parse --git-dir',{stdio:'ignore'});require('child_process').execSync('bash .githooks/install.sh',{stdio:'inherit'})}catch(e){console.warn('[i] Hook install skipped:',e.message)}"`,
|
|
63408
|
+
postinstall: "node bin/postinstall-self-heal.cjs",
|
|
63407
63409
|
"help:check-parity": "bun run scripts/check-help-parity.ts",
|
|
63408
63410
|
"manifest:generate": "bun run scripts/generate-cli-manifest.ts",
|
|
63409
63411
|
"docs:generate": "bun run scripts/generate-cli-reference.ts",
|
|
@@ -63903,7 +63905,10 @@ function isLegacyDescriptiveNamePrompt(entry) {
|
|
|
63903
63905
|
const prompt = entry.prompt;
|
|
63904
63906
|
if (entry.type !== "prompt" || typeof prompt !== "string")
|
|
63905
63907
|
return false;
|
|
63906
|
-
|
|
63908
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
63909
|
+
const isOriginalLegacyPrompt = prompt.includes("Use kebab-case file naming") && prompt.includes("self-documenting") && prompt.includes("Grep, Glob, Search");
|
|
63910
|
+
const isDescriptiveNameKebabPrompt = lowerPrompt.includes("descriptive-name") && lowerPrompt.includes("kebab-case") && (lowerPrompt.includes("file") || lowerPrompt.includes("filename"));
|
|
63911
|
+
return isOriginalLegacyPrompt || isDescriptiveNameKebabPrompt;
|
|
63907
63912
|
}
|
|
63908
63913
|
function extractHookFilePath(command, hookDir) {
|
|
63909
63914
|
if (!command)
|
|
@@ -63986,7 +63991,7 @@ var init_shared2 = __esm(() => {
|
|
|
63986
63991
|
|
|
63987
63992
|
// src/domains/health-checks/checkers/hook-health-checker.ts
|
|
63988
63993
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
63989
|
-
import { existsSync as existsSync45, readFileSync as readFileSync12, statSync as statSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
63994
|
+
import { existsSync as existsSync45, readFileSync as readFileSync12, readdirSync as readdirSync8, statSync as statSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
63990
63995
|
import { readdir as readdir17 } from "node:fs/promises";
|
|
63991
63996
|
import { homedir as homedir41, tmpdir } from "node:os";
|
|
63992
63997
|
import { join as join64, resolve as resolve33 } from "node:path";
|
|
@@ -64023,6 +64028,7 @@ function getCanonicalGlobalCommandRoot() {
|
|
|
64023
64028
|
}
|
|
64024
64029
|
function getClaudeSettingsFiles(projectDir) {
|
|
64025
64030
|
const globalClaudeDir = PathResolver.getGlobalKitDir();
|
|
64031
|
+
const ccsSettingsDir = join64(process.env.CK_TEST_HOME ?? homedir41(), ".ccs");
|
|
64026
64032
|
const candidates = [
|
|
64027
64033
|
{
|
|
64028
64034
|
path: resolve33(projectDir, ".claude", "settings.json"),
|
|
@@ -64045,6 +64051,17 @@ function getClaudeSettingsFiles(projectDir) {
|
|
|
64045
64051
|
root: getCanonicalGlobalCommandRoot()
|
|
64046
64052
|
}
|
|
64047
64053
|
];
|
|
64054
|
+
try {
|
|
64055
|
+
for (const dirent of readdirSync8(ccsSettingsDir, { withFileTypes: true })) {
|
|
64056
|
+
if (!dirent.isFile() || !dirent.name.endsWith(".settings.json"))
|
|
64057
|
+
continue;
|
|
64058
|
+
candidates.push({
|
|
64059
|
+
path: resolve33(ccsSettingsDir, dirent.name),
|
|
64060
|
+
label: `.ccs/${dirent.name}`,
|
|
64061
|
+
root: "$HOME"
|
|
64062
|
+
});
|
|
64063
|
+
}
|
|
64064
|
+
} catch {}
|
|
64048
64065
|
return candidates.filter((candidate) => existsSync45(candidate.path));
|
|
64049
64066
|
}
|
|
64050
64067
|
function isAlreadyCanonical(cmd) {
|
|
@@ -76416,7 +76433,7 @@ var init_content_validator = __esm(() => {
|
|
|
76416
76433
|
|
|
76417
76434
|
// src/commands/content/phases/context-cache-manager.ts
|
|
76418
76435
|
import { createHash as createHash9 } from "node:crypto";
|
|
76419
|
-
import { existsSync as existsSync79, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as
|
|
76436
|
+
import { existsSync as existsSync79, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as readdirSync13, statSync as statSync14 } from "node:fs";
|
|
76420
76437
|
import { rename as rename16, writeFile as writeFile40 } from "node:fs/promises";
|
|
76421
76438
|
import { homedir as homedir55 } from "node:os";
|
|
76422
76439
|
import { basename as basename34, join as join160 } from "node:path";
|
|
@@ -76465,7 +76482,7 @@ function getDocSourcePaths(repoPath) {
|
|
|
76465
76482
|
const docsDir = join160(repoPath, "docs");
|
|
76466
76483
|
if (existsSync79(docsDir)) {
|
|
76467
76484
|
try {
|
|
76468
|
-
const files =
|
|
76485
|
+
const files = readdirSync13(docsDir);
|
|
76469
76486
|
for (const f3 of files) {
|
|
76470
76487
|
if (f3.endsWith(".md"))
|
|
76471
76488
|
paths.push(join160(docsDir, f3));
|
|
@@ -76478,7 +76495,7 @@ function getDocSourcePaths(repoPath) {
|
|
|
76478
76495
|
const stylesDir = join160(repoPath, "assets", "writing-styles");
|
|
76479
76496
|
if (existsSync79(stylesDir)) {
|
|
76480
76497
|
try {
|
|
76481
|
-
const files =
|
|
76498
|
+
const files = readdirSync13(stylesDir);
|
|
76482
76499
|
for (const f3 of files) {
|
|
76483
76500
|
paths.push(join160(stylesDir, f3));
|
|
76484
76501
|
}
|
|
@@ -76673,7 +76690,7 @@ function extractContentFromResponse(response) {
|
|
|
76673
76690
|
|
|
76674
76691
|
// src/commands/content/phases/docs-summarizer.ts
|
|
76675
76692
|
import { execSync as execSync7 } from "node:child_process";
|
|
76676
|
-
import { existsSync as existsSync80, readFileSync as readFileSync19, readdirSync as
|
|
76693
|
+
import { existsSync as existsSync80, readFileSync as readFileSync19, readdirSync as readdirSync14 } from "node:fs";
|
|
76677
76694
|
import { join as join161 } from "node:path";
|
|
76678
76695
|
async function summarizeProjectDocs(repoPath, contentLogger) {
|
|
76679
76696
|
const rawContent = collectRawDocs(repoPath);
|
|
@@ -76731,7 +76748,7 @@ function collectRawDocs(repoPath) {
|
|
|
76731
76748
|
const docsDir = join161(repoPath, "docs");
|
|
76732
76749
|
if (existsSync80(docsDir)) {
|
|
76733
76750
|
try {
|
|
76734
|
-
const files =
|
|
76751
|
+
const files = readdirSync14(docsDir).filter((f3) => f3.endsWith(".md")).sort();
|
|
76735
76752
|
for (const f3 of files) {
|
|
76736
76753
|
const content = readCapped(join161(docsDir, f3), 5000);
|
|
76737
76754
|
if (content) {
|
|
@@ -76755,7 +76772,7 @@ ${content}`);
|
|
|
76755
76772
|
const stylesDir = join161(repoPath, "assets", "writing-styles");
|
|
76756
76773
|
if (existsSync80(stylesDir)) {
|
|
76757
76774
|
try {
|
|
76758
|
-
const files =
|
|
76775
|
+
const files = readdirSync14(stylesDir).slice(0, 3);
|
|
76759
76776
|
styles3 = files.map((f3) => readCapped(join161(stylesDir, f3), 1000)).filter(Boolean).join(`
|
|
76760
76777
|
|
|
76761
76778
|
`);
|
|
@@ -76946,7 +76963,7 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
|
|
|
76946
76963
|
|
|
76947
76964
|
// src/commands/content/phases/photo-generator.ts
|
|
76948
76965
|
import { execSync as execSync8 } from "node:child_process";
|
|
76949
|
-
import { existsSync as existsSync81, mkdirSync as mkdirSync6, readdirSync as
|
|
76966
|
+
import { existsSync as existsSync81, mkdirSync as mkdirSync6, readdirSync as readdirSync15 } from "node:fs";
|
|
76950
76967
|
import { homedir as homedir56 } from "node:os";
|
|
76951
76968
|
import { join as join162 } from "node:path";
|
|
76952
76969
|
async function generatePhoto(_content, context, config, platform18, contentId, contentLogger) {
|
|
@@ -76971,7 +76988,7 @@ async function generatePhoto(_content, context, config, platform18, contentId, c
|
|
|
76971
76988
|
return { path: imagePath, ...dimensions, format: "png" };
|
|
76972
76989
|
}
|
|
76973
76990
|
}
|
|
76974
|
-
const files =
|
|
76991
|
+
const files = readdirSync15(mediaDir);
|
|
76975
76992
|
const imageFile = files.find((f3) => /\.(png|jpg|jpeg|webp)$/i.test(f3));
|
|
76976
76993
|
if (imageFile) {
|
|
76977
76994
|
const ext2 = imageFile.split(".").pop() ?? "png";
|
|
@@ -77358,7 +77375,7 @@ function isNoiseCommit(title, author) {
|
|
|
77358
77375
|
|
|
77359
77376
|
// src/commands/content/phases/change-detector.ts
|
|
77360
77377
|
import { execSync as execSync10, spawnSync as spawnSync9 } from "node:child_process";
|
|
77361
|
-
import { existsSync as existsSync84, readFileSync as readFileSync20, readdirSync as
|
|
77378
|
+
import { existsSync as existsSync84, readFileSync as readFileSync20, readdirSync as readdirSync16, statSync as statSync16 } from "node:fs";
|
|
77362
77379
|
import { join as join164 } from "node:path";
|
|
77363
77380
|
function detectCommits(repo, since) {
|
|
77364
77381
|
try {
|
|
@@ -77474,7 +77491,7 @@ function detectCompletedPlans(repo, since) {
|
|
|
77474
77491
|
const sinceMs = new Date(since).getTime();
|
|
77475
77492
|
const events = [];
|
|
77476
77493
|
try {
|
|
77477
|
-
const entries =
|
|
77494
|
+
const entries = readdirSync16(plansDir, { withFileTypes: true });
|
|
77478
77495
|
for (const entry of entries) {
|
|
77479
77496
|
if (!entry.isDirectory())
|
|
77480
77497
|
continue;
|
|
@@ -77555,7 +77572,7 @@ function classifyCommit(event) {
|
|
|
77555
77572
|
|
|
77556
77573
|
// src/commands/content/phases/repo-discoverer.ts
|
|
77557
77574
|
import { execSync as execSync11 } from "node:child_process";
|
|
77558
|
-
import { readdirSync as
|
|
77575
|
+
import { readdirSync as readdirSync17 } from "node:fs";
|
|
77559
77576
|
import { join as join165 } from "node:path";
|
|
77560
77577
|
function discoverRepos2(cwd2) {
|
|
77561
77578
|
const repos = [];
|
|
@@ -77565,7 +77582,7 @@ function discoverRepos2(cwd2) {
|
|
|
77565
77582
|
repos.push(info);
|
|
77566
77583
|
}
|
|
77567
77584
|
try {
|
|
77568
|
-
const entries =
|
|
77585
|
+
const entries = readdirSync17(cwd2, { withFileTypes: true });
|
|
77569
77586
|
for (const entry of entries) {
|
|
77570
77587
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
77571
77588
|
continue;
|
|
@@ -100779,7 +100796,7 @@ async function handleDownload(ctx) {
|
|
|
100779
100796
|
import { join as join120 } from "node:path";
|
|
100780
100797
|
|
|
100781
100798
|
// src/domains/installation/deletion-handler.ts
|
|
100782
|
-
import { existsSync as existsSync65, lstatSync as lstatSync3, readdirSync as
|
|
100799
|
+
import { existsSync as existsSync65, lstatSync as lstatSync3, readdirSync as readdirSync9, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync4 } from "node:fs";
|
|
100783
100800
|
import { dirname as dirname35, join as join106, relative as relative21, resolve as resolve41, sep as sep12 } from "node:path";
|
|
100784
100801
|
|
|
100785
100802
|
// src/services/file-operations/manifest/manifest-reader.ts
|
|
@@ -100973,7 +100990,7 @@ function collectFilesRecursively(dir, baseDir) {
|
|
|
100973
100990
|
if (!existsSync65(dir))
|
|
100974
100991
|
return results;
|
|
100975
100992
|
try {
|
|
100976
|
-
const entries =
|
|
100993
|
+
const entries = readdirSync9(dir, { withFileTypes: true });
|
|
100977
100994
|
for (const entry of entries) {
|
|
100978
100995
|
const fullPath = join106(dir, entry.name);
|
|
100979
100996
|
const relativePath = relative21(baseDir, fullPath);
|
|
@@ -101011,7 +101028,7 @@ function cleanupEmptyDirectories(filePath, claudeDir3) {
|
|
|
101011
101028
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir) && iterations < MAX_CLEANUP_ITERATIONS) {
|
|
101012
101029
|
iterations++;
|
|
101013
101030
|
try {
|
|
101014
|
-
const entries =
|
|
101031
|
+
const entries = readdirSync9(currentDir);
|
|
101015
101032
|
if (entries.length === 0) {
|
|
101016
101033
|
rmdirSync(currentDir);
|
|
101017
101034
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
@@ -106747,7 +106764,7 @@ async function runPreflightChecks() {
|
|
|
106747
106764
|
|
|
106748
106765
|
// src/domains/installation/fresh-installer.ts
|
|
106749
106766
|
init_metadata_migration();
|
|
106750
|
-
import { existsSync as existsSync67, readdirSync as
|
|
106767
|
+
import { existsSync as existsSync67, readdirSync as readdirSync10, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
|
|
106751
106768
|
import { basename as basename28, dirname as dirname39, join as join132, resolve as resolve45 } from "node:path";
|
|
106752
106769
|
init_logger();
|
|
106753
106770
|
init_safe_spinner();
|
|
@@ -106804,7 +106821,7 @@ function cleanupEmptyDirectories2(filePath, claudeDir3) {
|
|
|
106804
106821
|
let currentDir = resolve45(dirname39(filePath));
|
|
106805
106822
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
|
|
106806
106823
|
try {
|
|
106807
|
-
const entries =
|
|
106824
|
+
const entries = readdirSync10(currentDir);
|
|
106808
106825
|
if (entries.length === 0) {
|
|
106809
106826
|
rmdirSync2(currentDir);
|
|
106810
106827
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
@@ -108487,6 +108504,19 @@ async function repairMissingHookFileReferencesAfterInit(ctx) {
|
|
|
108487
108504
|
logger.debug(`Hook file reference repair skipped after init: ${error instanceof Error ? error.message : "unknown"}`);
|
|
108488
108505
|
}
|
|
108489
108506
|
}
|
|
108507
|
+
async function repairLegacyHookPromptsAfterInit(ctx) {
|
|
108508
|
+
if (!ctx.resolvedDir)
|
|
108509
|
+
return;
|
|
108510
|
+
const projectDir = ctx.options.global ? process.cwd() : ctx.resolvedDir;
|
|
108511
|
+
try {
|
|
108512
|
+
const repaired = await repairLegacyHookPrompts(projectDir);
|
|
108513
|
+
if (repaired > 0) {
|
|
108514
|
+
logger.info(`Pruned ${repaired} legacy hook prompt(s)`);
|
|
108515
|
+
}
|
|
108516
|
+
} catch (error) {
|
|
108517
|
+
logger.debug(`Legacy hook prompt repair skipped after init: ${error instanceof Error ? error.message : "unknown"}`);
|
|
108518
|
+
}
|
|
108519
|
+
}
|
|
108490
108520
|
async function executeInit(options2, prompts) {
|
|
108491
108521
|
let ctx = createInitContext(options2, prompts);
|
|
108492
108522
|
ctx = await resolveOptions(ctx);
|
|
@@ -108560,6 +108590,7 @@ async function executeInit(options2, prompts) {
|
|
|
108560
108590
|
Installed ${installedKits.length} kits: ${installedKits.map((k2) => AVAILABLE_KITS[k2].name).join(", ")}`);
|
|
108561
108591
|
}
|
|
108562
108592
|
if (!isSyncMode) {
|
|
108593
|
+
await repairLegacyHookPromptsAfterInit(ctx);
|
|
108563
108594
|
await repairMissingHookFileReferencesAfterInit(ctx);
|
|
108564
108595
|
}
|
|
108565
108596
|
prompts.outro(`Project initialized successfully at ${ctx.resolvedDir}`);
|
|
@@ -113348,7 +113379,7 @@ async function detectInstallations() {
|
|
|
113348
113379
|
}
|
|
113349
113380
|
|
|
113350
113381
|
// src/commands/uninstall/removal-handler.ts
|
|
113351
|
-
import { readdirSync as
|
|
113382
|
+
import { readdirSync as readdirSync12, rmSync as rmSync5 } from "node:fs";
|
|
113352
113383
|
import { basename as basename33, join as join152, resolve as resolve58, sep as sep14 } from "node:path";
|
|
113353
113384
|
init_logger();
|
|
113354
113385
|
init_safe_prompts();
|
|
@@ -113357,7 +113388,7 @@ var import_fs_extra42 = __toESM(require_lib(), 1);
|
|
|
113357
113388
|
|
|
113358
113389
|
// src/commands/uninstall/analysis-handler.ts
|
|
113359
113390
|
init_metadata_migration();
|
|
113360
|
-
import { readdirSync as
|
|
113391
|
+
import { readdirSync as readdirSync11, rmSync as rmSync4 } from "node:fs";
|
|
113361
113392
|
import { dirname as dirname48, join as join151 } from "node:path";
|
|
113362
113393
|
init_logger();
|
|
113363
113394
|
init_safe_prompts();
|
|
@@ -113383,7 +113414,7 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
|
113383
113414
|
let currentDir = dirname48(filePath);
|
|
113384
113415
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
113385
113416
|
try {
|
|
113386
|
-
const entries =
|
|
113417
|
+
const entries = readdirSync11(currentDir);
|
|
113387
113418
|
if (entries.length === 0) {
|
|
113388
113419
|
rmSync4(currentDir, { recursive: true });
|
|
113389
113420
|
cleaned++;
|
|
@@ -113627,7 +113658,7 @@ async function removeInstallations(installations, options2) {
|
|
|
113627
113658
|
}
|
|
113628
113659
|
}
|
|
113629
113660
|
try {
|
|
113630
|
-
const remaining =
|
|
113661
|
+
const remaining = readdirSync12(installation.path);
|
|
113631
113662
|
if (remaining.length === 0) {
|
|
113632
113663
|
rmSync5(installation.path, { recursive: true });
|
|
113633
113664
|
logger.debug(`Removed empty installation directory: ${installation.path}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudekit-cli",
|
|
3
|
-
"version": "4.3.1-dev.
|
|
3
|
+
"version": "4.3.1-dev.12",
|
|
4
4
|
"description": "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"bin/ck.js",
|
|
19
|
+
"bin/postinstall-self-heal.cjs",
|
|
19
20
|
"dist/index.js",
|
|
20
21
|
"dist/ui/",
|
|
21
22
|
"cli-manifest.json"
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
"ci:local": "bash scripts/ci-local.sh",
|
|
48
49
|
"install:hooks": "./.githooks/install.sh",
|
|
49
50
|
"prepare": "node -e \"try{require('child_process').execSync('git rev-parse --git-dir',{stdio:'ignore'});require('child_process').execSync('bash .githooks/install.sh',{stdio:'inherit'})}catch(e){console.warn('[i] Hook install skipped:',e.message)}\"",
|
|
51
|
+
"postinstall": "node bin/postinstall-self-heal.cjs",
|
|
50
52
|
"help:check-parity": "bun run scripts/check-help-parity.ts",
|
|
51
53
|
"manifest:generate": "bun run scripts/generate-cli-manifest.ts",
|
|
52
54
|
"docs:generate": "bun run scripts/generate-cli-reference.ts",
|