claudekit-cli 3.10.1 → 3.11.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/index.js +1759 -411
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -6600,7 +6600,8 @@ var init_commands = __esm(() => {
|
|
|
6600
6600
|
global: exports_external.boolean().default(false),
|
|
6601
6601
|
all: exports_external.boolean().default(false),
|
|
6602
6602
|
dryRun: exports_external.boolean().default(false),
|
|
6603
|
-
forceOverwrite: exports_external.boolean().default(false)
|
|
6603
|
+
forceOverwrite: exports_external.boolean().default(false),
|
|
6604
|
+
kit: KitType.optional()
|
|
6604
6605
|
}).merge(GlobalOutputOptionsSchema);
|
|
6605
6606
|
UpdateCliOptionsSchema = exports_external.object({
|
|
6606
6607
|
release: exports_external.string().optional(),
|
|
@@ -6643,7 +6644,7 @@ var init_github = __esm(() => {
|
|
|
6643
6644
|
});
|
|
6644
6645
|
|
|
6645
6646
|
// src/types/metadata.ts
|
|
6646
|
-
var TrackedFileSchema, MetadataSchema, ConfigSchema;
|
|
6647
|
+
var TrackedFileSchema, KitMetadataSchema, MultiKitMetadataSchema, LegacyMetadataSchema, MetadataSchema, ConfigSchema;
|
|
6647
6648
|
var init_metadata = __esm(() => {
|
|
6648
6649
|
init_zod();
|
|
6649
6650
|
init_commands();
|
|
@@ -6654,7 +6655,22 @@ var init_metadata = __esm(() => {
|
|
|
6654
6655
|
ownership: exports_external.enum(["ck", "user", "ck-modified"]),
|
|
6655
6656
|
installedVersion: exports_external.string()
|
|
6656
6657
|
});
|
|
6657
|
-
|
|
6658
|
+
KitMetadataSchema = exports_external.object({
|
|
6659
|
+
version: exports_external.string(),
|
|
6660
|
+
installedAt: exports_external.string(),
|
|
6661
|
+
files: exports_external.array(TrackedFileSchema).optional()
|
|
6662
|
+
});
|
|
6663
|
+
MultiKitMetadataSchema = exports_external.object({
|
|
6664
|
+
kits: exports_external.record(KitType, KitMetadataSchema).optional(),
|
|
6665
|
+
scope: exports_external.enum(["local", "global"]).optional(),
|
|
6666
|
+
name: exports_external.string().optional(),
|
|
6667
|
+
version: exports_external.string().optional(),
|
|
6668
|
+
installedAt: exports_external.string().optional(),
|
|
6669
|
+
installedFiles: exports_external.array(exports_external.string()).optional(),
|
|
6670
|
+
userConfigFiles: exports_external.array(exports_external.string()).optional(),
|
|
6671
|
+
files: exports_external.array(TrackedFileSchema).optional()
|
|
6672
|
+
});
|
|
6673
|
+
LegacyMetadataSchema = exports_external.object({
|
|
6658
6674
|
name: exports_external.string().optional(),
|
|
6659
6675
|
version: exports_external.string().optional(),
|
|
6660
6676
|
installedAt: exports_external.string().optional(),
|
|
@@ -6663,6 +6679,7 @@ var init_metadata = __esm(() => {
|
|
|
6663
6679
|
userConfigFiles: exports_external.array(exports_external.string()).optional(),
|
|
6664
6680
|
files: exports_external.array(TrackedFileSchema).optional()
|
|
6665
6681
|
});
|
|
6682
|
+
MetadataSchema = MultiKitMetadataSchema;
|
|
6666
6683
|
ConfigSchema = exports_external.object({
|
|
6667
6684
|
defaults: exports_external.object({
|
|
6668
6685
|
kit: KitType.optional(),
|
|
@@ -6747,8 +6764,11 @@ __export(exports_types, {
|
|
|
6747
6764
|
PROTECTED_PATTERNS: () => PROTECTED_PATTERNS,
|
|
6748
6765
|
NewCommandOptionsSchema: () => NewCommandOptionsSchema,
|
|
6749
6766
|
NEVER_COPY_PATTERNS: () => NEVER_COPY_PATTERNS,
|
|
6767
|
+
MultiKitMetadataSchema: () => MultiKitMetadataSchema,
|
|
6750
6768
|
MetadataSchema: () => MetadataSchema,
|
|
6769
|
+
LegacyMetadataSchema: () => LegacyMetadataSchema,
|
|
6751
6770
|
KitType: () => KitType,
|
|
6771
|
+
KitMetadataSchema: () => KitMetadataSchema,
|
|
6752
6772
|
KitConfigSchema: () => KitConfigSchema,
|
|
6753
6773
|
GitHubReleaseSchema: () => GitHubReleaseSchema,
|
|
6754
6774
|
GitHubReleaseAssetSchema: () => GitHubReleaseAssetSchema,
|
|
@@ -6895,7 +6915,7 @@ var require_umd = __commonJS((exports, module) => {
|
|
|
6895
6915
|
});
|
|
6896
6916
|
|
|
6897
6917
|
// src/shared/environment.ts
|
|
6898
|
-
function
|
|
6918
|
+
function isCIEnvironment() {
|
|
6899
6919
|
return process.env.CI === "true" || process.env.CI_SAFE_MODE === "true";
|
|
6900
6920
|
}
|
|
6901
6921
|
function isNonInteractive() {
|
|
@@ -12253,9 +12273,751 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
12253
12273
|
}
|
|
12254
12274
|
});
|
|
12255
12275
|
|
|
12276
|
+
// node_modules/retry/lib/retry_operation.js
|
|
12277
|
+
var require_retry_operation = __commonJS((exports, module) => {
|
|
12278
|
+
function RetryOperation(timeouts, options) {
|
|
12279
|
+
if (typeof options === "boolean") {
|
|
12280
|
+
options = { forever: options };
|
|
12281
|
+
}
|
|
12282
|
+
this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
|
|
12283
|
+
this._timeouts = timeouts;
|
|
12284
|
+
this._options = options || {};
|
|
12285
|
+
this._maxRetryTime = options && options.maxRetryTime || Infinity;
|
|
12286
|
+
this._fn = null;
|
|
12287
|
+
this._errors = [];
|
|
12288
|
+
this._attempts = 1;
|
|
12289
|
+
this._operationTimeout = null;
|
|
12290
|
+
this._operationTimeoutCb = null;
|
|
12291
|
+
this._timeout = null;
|
|
12292
|
+
this._operationStart = null;
|
|
12293
|
+
if (this._options.forever) {
|
|
12294
|
+
this._cachedTimeouts = this._timeouts.slice(0);
|
|
12295
|
+
}
|
|
12296
|
+
}
|
|
12297
|
+
module.exports = RetryOperation;
|
|
12298
|
+
RetryOperation.prototype.reset = function() {
|
|
12299
|
+
this._attempts = 1;
|
|
12300
|
+
this._timeouts = this._originalTimeouts;
|
|
12301
|
+
};
|
|
12302
|
+
RetryOperation.prototype.stop = function() {
|
|
12303
|
+
if (this._timeout) {
|
|
12304
|
+
clearTimeout(this._timeout);
|
|
12305
|
+
}
|
|
12306
|
+
this._timeouts = [];
|
|
12307
|
+
this._cachedTimeouts = null;
|
|
12308
|
+
};
|
|
12309
|
+
RetryOperation.prototype.retry = function(err) {
|
|
12310
|
+
if (this._timeout) {
|
|
12311
|
+
clearTimeout(this._timeout);
|
|
12312
|
+
}
|
|
12313
|
+
if (!err) {
|
|
12314
|
+
return false;
|
|
12315
|
+
}
|
|
12316
|
+
var currentTime = new Date().getTime();
|
|
12317
|
+
if (err && currentTime - this._operationStart >= this._maxRetryTime) {
|
|
12318
|
+
this._errors.unshift(new Error("RetryOperation timeout occurred"));
|
|
12319
|
+
return false;
|
|
12320
|
+
}
|
|
12321
|
+
this._errors.push(err);
|
|
12322
|
+
var timeout = this._timeouts.shift();
|
|
12323
|
+
if (timeout === undefined) {
|
|
12324
|
+
if (this._cachedTimeouts) {
|
|
12325
|
+
this._errors.splice(this._errors.length - 1, this._errors.length);
|
|
12326
|
+
this._timeouts = this._cachedTimeouts.slice(0);
|
|
12327
|
+
timeout = this._timeouts.shift();
|
|
12328
|
+
} else {
|
|
12329
|
+
return false;
|
|
12330
|
+
}
|
|
12331
|
+
}
|
|
12332
|
+
var self2 = this;
|
|
12333
|
+
var timer = setTimeout(function() {
|
|
12334
|
+
self2._attempts++;
|
|
12335
|
+
if (self2._operationTimeoutCb) {
|
|
12336
|
+
self2._timeout = setTimeout(function() {
|
|
12337
|
+
self2._operationTimeoutCb(self2._attempts);
|
|
12338
|
+
}, self2._operationTimeout);
|
|
12339
|
+
if (self2._options.unref) {
|
|
12340
|
+
self2._timeout.unref();
|
|
12341
|
+
}
|
|
12342
|
+
}
|
|
12343
|
+
self2._fn(self2._attempts);
|
|
12344
|
+
}, timeout);
|
|
12345
|
+
if (this._options.unref) {
|
|
12346
|
+
timer.unref();
|
|
12347
|
+
}
|
|
12348
|
+
return true;
|
|
12349
|
+
};
|
|
12350
|
+
RetryOperation.prototype.attempt = function(fn, timeoutOps) {
|
|
12351
|
+
this._fn = fn;
|
|
12352
|
+
if (timeoutOps) {
|
|
12353
|
+
if (timeoutOps.timeout) {
|
|
12354
|
+
this._operationTimeout = timeoutOps.timeout;
|
|
12355
|
+
}
|
|
12356
|
+
if (timeoutOps.cb) {
|
|
12357
|
+
this._operationTimeoutCb = timeoutOps.cb;
|
|
12358
|
+
}
|
|
12359
|
+
}
|
|
12360
|
+
var self2 = this;
|
|
12361
|
+
if (this._operationTimeoutCb) {
|
|
12362
|
+
this._timeout = setTimeout(function() {
|
|
12363
|
+
self2._operationTimeoutCb();
|
|
12364
|
+
}, self2._operationTimeout);
|
|
12365
|
+
}
|
|
12366
|
+
this._operationStart = new Date().getTime();
|
|
12367
|
+
this._fn(this._attempts);
|
|
12368
|
+
};
|
|
12369
|
+
RetryOperation.prototype.try = function(fn) {
|
|
12370
|
+
console.log("Using RetryOperation.try() is deprecated");
|
|
12371
|
+
this.attempt(fn);
|
|
12372
|
+
};
|
|
12373
|
+
RetryOperation.prototype.start = function(fn) {
|
|
12374
|
+
console.log("Using RetryOperation.start() is deprecated");
|
|
12375
|
+
this.attempt(fn);
|
|
12376
|
+
};
|
|
12377
|
+
RetryOperation.prototype.start = RetryOperation.prototype.try;
|
|
12378
|
+
RetryOperation.prototype.errors = function() {
|
|
12379
|
+
return this._errors;
|
|
12380
|
+
};
|
|
12381
|
+
RetryOperation.prototype.attempts = function() {
|
|
12382
|
+
return this._attempts;
|
|
12383
|
+
};
|
|
12384
|
+
RetryOperation.prototype.mainError = function() {
|
|
12385
|
+
if (this._errors.length === 0) {
|
|
12386
|
+
return null;
|
|
12387
|
+
}
|
|
12388
|
+
var counts = {};
|
|
12389
|
+
var mainError = null;
|
|
12390
|
+
var mainErrorCount = 0;
|
|
12391
|
+
for (var i = 0;i < this._errors.length; i++) {
|
|
12392
|
+
var error = this._errors[i];
|
|
12393
|
+
var message = error.message;
|
|
12394
|
+
var count = (counts[message] || 0) + 1;
|
|
12395
|
+
counts[message] = count;
|
|
12396
|
+
if (count >= mainErrorCount) {
|
|
12397
|
+
mainError = error;
|
|
12398
|
+
mainErrorCount = count;
|
|
12399
|
+
}
|
|
12400
|
+
}
|
|
12401
|
+
return mainError;
|
|
12402
|
+
};
|
|
12403
|
+
});
|
|
12404
|
+
|
|
12405
|
+
// node_modules/retry/lib/retry.js
|
|
12406
|
+
var require_retry = __commonJS((exports) => {
|
|
12407
|
+
var RetryOperation = require_retry_operation();
|
|
12408
|
+
exports.operation = function(options) {
|
|
12409
|
+
var timeouts = exports.timeouts(options);
|
|
12410
|
+
return new RetryOperation(timeouts, {
|
|
12411
|
+
forever: options && options.forever,
|
|
12412
|
+
unref: options && options.unref,
|
|
12413
|
+
maxRetryTime: options && options.maxRetryTime
|
|
12414
|
+
});
|
|
12415
|
+
};
|
|
12416
|
+
exports.timeouts = function(options) {
|
|
12417
|
+
if (options instanceof Array) {
|
|
12418
|
+
return [].concat(options);
|
|
12419
|
+
}
|
|
12420
|
+
var opts = {
|
|
12421
|
+
retries: 10,
|
|
12422
|
+
factor: 2,
|
|
12423
|
+
minTimeout: 1 * 1000,
|
|
12424
|
+
maxTimeout: Infinity,
|
|
12425
|
+
randomize: false
|
|
12426
|
+
};
|
|
12427
|
+
for (var key in options) {
|
|
12428
|
+
opts[key] = options[key];
|
|
12429
|
+
}
|
|
12430
|
+
if (opts.minTimeout > opts.maxTimeout) {
|
|
12431
|
+
throw new Error("minTimeout is greater than maxTimeout");
|
|
12432
|
+
}
|
|
12433
|
+
var timeouts = [];
|
|
12434
|
+
for (var i = 0;i < opts.retries; i++) {
|
|
12435
|
+
timeouts.push(this.createTimeout(i, opts));
|
|
12436
|
+
}
|
|
12437
|
+
if (options && options.forever && !timeouts.length) {
|
|
12438
|
+
timeouts.push(this.createTimeout(i, opts));
|
|
12439
|
+
}
|
|
12440
|
+
timeouts.sort(function(a3, b3) {
|
|
12441
|
+
return a3 - b3;
|
|
12442
|
+
});
|
|
12443
|
+
return timeouts;
|
|
12444
|
+
};
|
|
12445
|
+
exports.createTimeout = function(attempt, opts) {
|
|
12446
|
+
var random = opts.randomize ? Math.random() + 1 : 1;
|
|
12447
|
+
var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt));
|
|
12448
|
+
timeout = Math.min(timeout, opts.maxTimeout);
|
|
12449
|
+
return timeout;
|
|
12450
|
+
};
|
|
12451
|
+
exports.wrap = function(obj, options, methods) {
|
|
12452
|
+
if (options instanceof Array) {
|
|
12453
|
+
methods = options;
|
|
12454
|
+
options = null;
|
|
12455
|
+
}
|
|
12456
|
+
if (!methods) {
|
|
12457
|
+
methods = [];
|
|
12458
|
+
for (var key in obj) {
|
|
12459
|
+
if (typeof obj[key] === "function") {
|
|
12460
|
+
methods.push(key);
|
|
12461
|
+
}
|
|
12462
|
+
}
|
|
12463
|
+
}
|
|
12464
|
+
for (var i = 0;i < methods.length; i++) {
|
|
12465
|
+
var method = methods[i];
|
|
12466
|
+
var original = obj[method];
|
|
12467
|
+
obj[method] = function retryWrapper(original2) {
|
|
12468
|
+
var op = exports.operation(options);
|
|
12469
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
12470
|
+
var callback = args.pop();
|
|
12471
|
+
args.push(function(err) {
|
|
12472
|
+
if (op.retry(err)) {
|
|
12473
|
+
return;
|
|
12474
|
+
}
|
|
12475
|
+
if (err) {
|
|
12476
|
+
arguments[0] = op.mainError();
|
|
12477
|
+
}
|
|
12478
|
+
callback.apply(this, arguments);
|
|
12479
|
+
});
|
|
12480
|
+
op.attempt(function() {
|
|
12481
|
+
original2.apply(obj, args);
|
|
12482
|
+
});
|
|
12483
|
+
}.bind(obj, original);
|
|
12484
|
+
obj[method].options = options;
|
|
12485
|
+
}
|
|
12486
|
+
};
|
|
12487
|
+
});
|
|
12488
|
+
|
|
12489
|
+
// node_modules/signal-exit/signals.js
|
|
12490
|
+
var require_signals = __commonJS((exports, module) => {
|
|
12491
|
+
module.exports = [
|
|
12492
|
+
"SIGABRT",
|
|
12493
|
+
"SIGALRM",
|
|
12494
|
+
"SIGHUP",
|
|
12495
|
+
"SIGINT",
|
|
12496
|
+
"SIGTERM"
|
|
12497
|
+
];
|
|
12498
|
+
if (process.platform !== "win32") {
|
|
12499
|
+
module.exports.push("SIGVTALRM", "SIGXCPU", "SIGXFSZ", "SIGUSR2", "SIGTRAP", "SIGSYS", "SIGQUIT", "SIGIOT");
|
|
12500
|
+
}
|
|
12501
|
+
if (process.platform === "linux") {
|
|
12502
|
+
module.exports.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT", "SIGUNUSED");
|
|
12503
|
+
}
|
|
12504
|
+
});
|
|
12505
|
+
|
|
12506
|
+
// node_modules/signal-exit/index.js
|
|
12507
|
+
var require_signal_exit = __commonJS((exports, module) => {
|
|
12508
|
+
var process10 = global.process;
|
|
12509
|
+
var processOk2 = function(process11) {
|
|
12510
|
+
return process11 && typeof process11 === "object" && typeof process11.removeListener === "function" && typeof process11.emit === "function" && typeof process11.reallyExit === "function" && typeof process11.listeners === "function" && typeof process11.kill === "function" && typeof process11.pid === "number" && typeof process11.on === "function";
|
|
12511
|
+
};
|
|
12512
|
+
if (!processOk2(process10)) {
|
|
12513
|
+
module.exports = function() {
|
|
12514
|
+
return function() {};
|
|
12515
|
+
};
|
|
12516
|
+
} else {
|
|
12517
|
+
assert3 = __require("assert");
|
|
12518
|
+
signals2 = require_signals();
|
|
12519
|
+
isWin = /^win/i.test(process10.platform);
|
|
12520
|
+
EE3 = __require("events");
|
|
12521
|
+
if (typeof EE3 !== "function") {
|
|
12522
|
+
EE3 = EE3.EventEmitter;
|
|
12523
|
+
}
|
|
12524
|
+
if (process10.__signal_exit_emitter__) {
|
|
12525
|
+
emitter = process10.__signal_exit_emitter__;
|
|
12526
|
+
} else {
|
|
12527
|
+
emitter = process10.__signal_exit_emitter__ = new EE3;
|
|
12528
|
+
emitter.count = 0;
|
|
12529
|
+
emitter.emitted = {};
|
|
12530
|
+
}
|
|
12531
|
+
if (!emitter.infinite) {
|
|
12532
|
+
emitter.setMaxListeners(Infinity);
|
|
12533
|
+
emitter.infinite = true;
|
|
12534
|
+
}
|
|
12535
|
+
module.exports = function(cb, opts) {
|
|
12536
|
+
if (!processOk2(global.process)) {
|
|
12537
|
+
return function() {};
|
|
12538
|
+
}
|
|
12539
|
+
assert3.equal(typeof cb, "function", "a callback must be provided for exit handler");
|
|
12540
|
+
if (loaded === false) {
|
|
12541
|
+
load2();
|
|
12542
|
+
}
|
|
12543
|
+
var ev = "exit";
|
|
12544
|
+
if (opts && opts.alwaysLast) {
|
|
12545
|
+
ev = "afterexit";
|
|
12546
|
+
}
|
|
12547
|
+
var remove = function() {
|
|
12548
|
+
emitter.removeListener(ev, cb);
|
|
12549
|
+
if (emitter.listeners("exit").length === 0 && emitter.listeners("afterexit").length === 0) {
|
|
12550
|
+
unload2();
|
|
12551
|
+
}
|
|
12552
|
+
};
|
|
12553
|
+
emitter.on(ev, cb);
|
|
12554
|
+
return remove;
|
|
12555
|
+
};
|
|
12556
|
+
unload2 = function unload() {
|
|
12557
|
+
if (!loaded || !processOk2(global.process)) {
|
|
12558
|
+
return;
|
|
12559
|
+
}
|
|
12560
|
+
loaded = false;
|
|
12561
|
+
signals2.forEach(function(sig) {
|
|
12562
|
+
try {
|
|
12563
|
+
process10.removeListener(sig, sigListeners[sig]);
|
|
12564
|
+
} catch (er) {}
|
|
12565
|
+
});
|
|
12566
|
+
process10.emit = originalProcessEmit;
|
|
12567
|
+
process10.reallyExit = originalProcessReallyExit;
|
|
12568
|
+
emitter.count -= 1;
|
|
12569
|
+
};
|
|
12570
|
+
module.exports.unload = unload2;
|
|
12571
|
+
emit = function emit(event, code2, signal) {
|
|
12572
|
+
if (emitter.emitted[event]) {
|
|
12573
|
+
return;
|
|
12574
|
+
}
|
|
12575
|
+
emitter.emitted[event] = true;
|
|
12576
|
+
emitter.emit(event, code2, signal);
|
|
12577
|
+
};
|
|
12578
|
+
sigListeners = {};
|
|
12579
|
+
signals2.forEach(function(sig) {
|
|
12580
|
+
sigListeners[sig] = function listener() {
|
|
12581
|
+
if (!processOk2(global.process)) {
|
|
12582
|
+
return;
|
|
12583
|
+
}
|
|
12584
|
+
var listeners = process10.listeners(sig);
|
|
12585
|
+
if (listeners.length === emitter.count) {
|
|
12586
|
+
unload2();
|
|
12587
|
+
emit("exit", null, sig);
|
|
12588
|
+
emit("afterexit", null, sig);
|
|
12589
|
+
if (isWin && sig === "SIGHUP") {
|
|
12590
|
+
sig = "SIGINT";
|
|
12591
|
+
}
|
|
12592
|
+
process10.kill(process10.pid, sig);
|
|
12593
|
+
}
|
|
12594
|
+
};
|
|
12595
|
+
});
|
|
12596
|
+
module.exports.signals = function() {
|
|
12597
|
+
return signals2;
|
|
12598
|
+
};
|
|
12599
|
+
loaded = false;
|
|
12600
|
+
load2 = function load() {
|
|
12601
|
+
if (loaded || !processOk2(global.process)) {
|
|
12602
|
+
return;
|
|
12603
|
+
}
|
|
12604
|
+
loaded = true;
|
|
12605
|
+
emitter.count += 1;
|
|
12606
|
+
signals2 = signals2.filter(function(sig) {
|
|
12607
|
+
try {
|
|
12608
|
+
process10.on(sig, sigListeners[sig]);
|
|
12609
|
+
return true;
|
|
12610
|
+
} catch (er) {
|
|
12611
|
+
return false;
|
|
12612
|
+
}
|
|
12613
|
+
});
|
|
12614
|
+
process10.emit = processEmit;
|
|
12615
|
+
process10.reallyExit = processReallyExit;
|
|
12616
|
+
};
|
|
12617
|
+
module.exports.load = load2;
|
|
12618
|
+
originalProcessReallyExit = process10.reallyExit;
|
|
12619
|
+
processReallyExit = function processReallyExit(code2) {
|
|
12620
|
+
if (!processOk2(global.process)) {
|
|
12621
|
+
return;
|
|
12622
|
+
}
|
|
12623
|
+
process10.exitCode = code2 || 0;
|
|
12624
|
+
emit("exit", process10.exitCode, null);
|
|
12625
|
+
emit("afterexit", process10.exitCode, null);
|
|
12626
|
+
originalProcessReallyExit.call(process10, process10.exitCode);
|
|
12627
|
+
};
|
|
12628
|
+
originalProcessEmit = process10.emit;
|
|
12629
|
+
processEmit = function processEmit(ev, arg) {
|
|
12630
|
+
if (ev === "exit" && processOk2(global.process)) {
|
|
12631
|
+
if (arg !== undefined) {
|
|
12632
|
+
process10.exitCode = arg;
|
|
12633
|
+
}
|
|
12634
|
+
var ret = originalProcessEmit.apply(this, arguments);
|
|
12635
|
+
emit("exit", process10.exitCode, null);
|
|
12636
|
+
emit("afterexit", process10.exitCode, null);
|
|
12637
|
+
return ret;
|
|
12638
|
+
} else {
|
|
12639
|
+
return originalProcessEmit.apply(this, arguments);
|
|
12640
|
+
}
|
|
12641
|
+
};
|
|
12642
|
+
}
|
|
12643
|
+
var assert3;
|
|
12644
|
+
var signals2;
|
|
12645
|
+
var isWin;
|
|
12646
|
+
var EE3;
|
|
12647
|
+
var emitter;
|
|
12648
|
+
var unload2;
|
|
12649
|
+
var emit;
|
|
12650
|
+
var sigListeners;
|
|
12651
|
+
var loaded;
|
|
12652
|
+
var load2;
|
|
12653
|
+
var originalProcessReallyExit;
|
|
12654
|
+
var processReallyExit;
|
|
12655
|
+
var originalProcessEmit;
|
|
12656
|
+
var processEmit;
|
|
12657
|
+
});
|
|
12658
|
+
|
|
12659
|
+
// node_modules/proper-lockfile/lib/mtime-precision.js
|
|
12660
|
+
var require_mtime_precision = __commonJS((exports, module) => {
|
|
12661
|
+
var cacheSymbol = Symbol();
|
|
12662
|
+
function probe(file, fs12, callback) {
|
|
12663
|
+
const cachedPrecision = fs12[cacheSymbol];
|
|
12664
|
+
if (cachedPrecision) {
|
|
12665
|
+
return fs12.stat(file, (err, stat3) => {
|
|
12666
|
+
if (err) {
|
|
12667
|
+
return callback(err);
|
|
12668
|
+
}
|
|
12669
|
+
callback(null, stat3.mtime, cachedPrecision);
|
|
12670
|
+
});
|
|
12671
|
+
}
|
|
12672
|
+
const mtime = new Date(Math.ceil(Date.now() / 1000) * 1000 + 5);
|
|
12673
|
+
fs12.utimes(file, mtime, mtime, (err) => {
|
|
12674
|
+
if (err) {
|
|
12675
|
+
return callback(err);
|
|
12676
|
+
}
|
|
12677
|
+
fs12.stat(file, (err2, stat3) => {
|
|
12678
|
+
if (err2) {
|
|
12679
|
+
return callback(err2);
|
|
12680
|
+
}
|
|
12681
|
+
const precision = stat3.mtime.getTime() % 1000 === 0 ? "s" : "ms";
|
|
12682
|
+
Object.defineProperty(fs12, cacheSymbol, { value: precision });
|
|
12683
|
+
callback(null, stat3.mtime, precision);
|
|
12684
|
+
});
|
|
12685
|
+
});
|
|
12686
|
+
}
|
|
12687
|
+
function getMtime(precision) {
|
|
12688
|
+
let now = Date.now();
|
|
12689
|
+
if (precision === "s") {
|
|
12690
|
+
now = Math.ceil(now / 1000) * 1000;
|
|
12691
|
+
}
|
|
12692
|
+
return new Date(now);
|
|
12693
|
+
}
|
|
12694
|
+
exports.probe = probe;
|
|
12695
|
+
exports.getMtime = getMtime;
|
|
12696
|
+
});
|
|
12697
|
+
|
|
12698
|
+
// node_modules/proper-lockfile/lib/lockfile.js
|
|
12699
|
+
var require_lockfile = __commonJS((exports, module) => {
|
|
12700
|
+
var path9 = __require("path");
|
|
12701
|
+
var fs12 = require_graceful_fs();
|
|
12702
|
+
var retry = require_retry();
|
|
12703
|
+
var onExit2 = require_signal_exit();
|
|
12704
|
+
var mtimePrecision = require_mtime_precision();
|
|
12705
|
+
var locks = {};
|
|
12706
|
+
function getLockFile(file, options) {
|
|
12707
|
+
return options.lockfilePath || `${file}.lock`;
|
|
12708
|
+
}
|
|
12709
|
+
function resolveCanonicalPath(file, options, callback) {
|
|
12710
|
+
if (!options.realpath) {
|
|
12711
|
+
return callback(null, path9.resolve(file));
|
|
12712
|
+
}
|
|
12713
|
+
options.fs.realpath(file, callback);
|
|
12714
|
+
}
|
|
12715
|
+
function acquireLock(file, options, callback) {
|
|
12716
|
+
const lockfilePath = getLockFile(file, options);
|
|
12717
|
+
options.fs.mkdir(lockfilePath, (err) => {
|
|
12718
|
+
if (!err) {
|
|
12719
|
+
return mtimePrecision.probe(lockfilePath, options.fs, (err2, mtime, mtimePrecision2) => {
|
|
12720
|
+
if (err2) {
|
|
12721
|
+
options.fs.rmdir(lockfilePath, () => {});
|
|
12722
|
+
return callback(err2);
|
|
12723
|
+
}
|
|
12724
|
+
callback(null, mtime, mtimePrecision2);
|
|
12725
|
+
});
|
|
12726
|
+
}
|
|
12727
|
+
if (err.code !== "EEXIST") {
|
|
12728
|
+
return callback(err);
|
|
12729
|
+
}
|
|
12730
|
+
if (options.stale <= 0) {
|
|
12731
|
+
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
12732
|
+
}
|
|
12733
|
+
options.fs.stat(lockfilePath, (err2, stat3) => {
|
|
12734
|
+
if (err2) {
|
|
12735
|
+
if (err2.code === "ENOENT") {
|
|
12736
|
+
return acquireLock(file, { ...options, stale: 0 }, callback);
|
|
12737
|
+
}
|
|
12738
|
+
return callback(err2);
|
|
12739
|
+
}
|
|
12740
|
+
if (!isLockStale(stat3, options)) {
|
|
12741
|
+
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
12742
|
+
}
|
|
12743
|
+
removeLock(file, options, (err3) => {
|
|
12744
|
+
if (err3) {
|
|
12745
|
+
return callback(err3);
|
|
12746
|
+
}
|
|
12747
|
+
acquireLock(file, { ...options, stale: 0 }, callback);
|
|
12748
|
+
});
|
|
12749
|
+
});
|
|
12750
|
+
});
|
|
12751
|
+
}
|
|
12752
|
+
function isLockStale(stat3, options) {
|
|
12753
|
+
return stat3.mtime.getTime() < Date.now() - options.stale;
|
|
12754
|
+
}
|
|
12755
|
+
function removeLock(file, options, callback) {
|
|
12756
|
+
options.fs.rmdir(getLockFile(file, options), (err) => {
|
|
12757
|
+
if (err && err.code !== "ENOENT") {
|
|
12758
|
+
return callback(err);
|
|
12759
|
+
}
|
|
12760
|
+
callback();
|
|
12761
|
+
});
|
|
12762
|
+
}
|
|
12763
|
+
function updateLock(file, options) {
|
|
12764
|
+
const lock2 = locks[file];
|
|
12765
|
+
if (lock2.updateTimeout) {
|
|
12766
|
+
return;
|
|
12767
|
+
}
|
|
12768
|
+
lock2.updateDelay = lock2.updateDelay || options.update;
|
|
12769
|
+
lock2.updateTimeout = setTimeout(() => {
|
|
12770
|
+
lock2.updateTimeout = null;
|
|
12771
|
+
options.fs.stat(lock2.lockfilePath, (err, stat3) => {
|
|
12772
|
+
const isOverThreshold = lock2.lastUpdate + options.stale < Date.now();
|
|
12773
|
+
if (err) {
|
|
12774
|
+
if (err.code === "ENOENT" || isOverThreshold) {
|
|
12775
|
+
return setLockAsCompromised(file, lock2, Object.assign(err, { code: "ECOMPROMISED" }));
|
|
12776
|
+
}
|
|
12777
|
+
lock2.updateDelay = 1000;
|
|
12778
|
+
return updateLock(file, options);
|
|
12779
|
+
}
|
|
12780
|
+
const isMtimeOurs = lock2.mtime.getTime() === stat3.mtime.getTime();
|
|
12781
|
+
if (!isMtimeOurs) {
|
|
12782
|
+
return setLockAsCompromised(file, lock2, Object.assign(new Error("Unable to update lock within the stale threshold"), { code: "ECOMPROMISED" }));
|
|
12783
|
+
}
|
|
12784
|
+
const mtime = mtimePrecision.getMtime(lock2.mtimePrecision);
|
|
12785
|
+
options.fs.utimes(lock2.lockfilePath, mtime, mtime, (err2) => {
|
|
12786
|
+
const isOverThreshold2 = lock2.lastUpdate + options.stale < Date.now();
|
|
12787
|
+
if (lock2.released) {
|
|
12788
|
+
return;
|
|
12789
|
+
}
|
|
12790
|
+
if (err2) {
|
|
12791
|
+
if (err2.code === "ENOENT" || isOverThreshold2) {
|
|
12792
|
+
return setLockAsCompromised(file, lock2, Object.assign(err2, { code: "ECOMPROMISED" }));
|
|
12793
|
+
}
|
|
12794
|
+
lock2.updateDelay = 1000;
|
|
12795
|
+
return updateLock(file, options);
|
|
12796
|
+
}
|
|
12797
|
+
lock2.mtime = mtime;
|
|
12798
|
+
lock2.lastUpdate = Date.now();
|
|
12799
|
+
lock2.updateDelay = null;
|
|
12800
|
+
updateLock(file, options);
|
|
12801
|
+
});
|
|
12802
|
+
});
|
|
12803
|
+
}, lock2.updateDelay);
|
|
12804
|
+
if (lock2.updateTimeout.unref) {
|
|
12805
|
+
lock2.updateTimeout.unref();
|
|
12806
|
+
}
|
|
12807
|
+
}
|
|
12808
|
+
function setLockAsCompromised(file, lock2, err) {
|
|
12809
|
+
lock2.released = true;
|
|
12810
|
+
if (lock2.updateTimeout) {
|
|
12811
|
+
clearTimeout(lock2.updateTimeout);
|
|
12812
|
+
}
|
|
12813
|
+
if (locks[file] === lock2) {
|
|
12814
|
+
delete locks[file];
|
|
12815
|
+
}
|
|
12816
|
+
lock2.options.onCompromised(err);
|
|
12817
|
+
}
|
|
12818
|
+
function lock(file, options, callback) {
|
|
12819
|
+
options = {
|
|
12820
|
+
stale: 1e4,
|
|
12821
|
+
update: null,
|
|
12822
|
+
realpath: true,
|
|
12823
|
+
retries: 0,
|
|
12824
|
+
fs: fs12,
|
|
12825
|
+
onCompromised: (err) => {
|
|
12826
|
+
throw err;
|
|
12827
|
+
},
|
|
12828
|
+
...options
|
|
12829
|
+
};
|
|
12830
|
+
options.retries = options.retries || 0;
|
|
12831
|
+
options.retries = typeof options.retries === "number" ? { retries: options.retries } : options.retries;
|
|
12832
|
+
options.stale = Math.max(options.stale || 0, 2000);
|
|
12833
|
+
options.update = options.update == null ? options.stale / 2 : options.update || 0;
|
|
12834
|
+
options.update = Math.max(Math.min(options.update, options.stale / 2), 1000);
|
|
12835
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
12836
|
+
if (err) {
|
|
12837
|
+
return callback(err);
|
|
12838
|
+
}
|
|
12839
|
+
const operation = retry.operation(options.retries);
|
|
12840
|
+
operation.attempt(() => {
|
|
12841
|
+
acquireLock(file2, options, (err2, mtime, mtimePrecision2) => {
|
|
12842
|
+
if (operation.retry(err2)) {
|
|
12843
|
+
return;
|
|
12844
|
+
}
|
|
12845
|
+
if (err2) {
|
|
12846
|
+
return callback(operation.mainError());
|
|
12847
|
+
}
|
|
12848
|
+
const lock2 = locks[file2] = {
|
|
12849
|
+
lockfilePath: getLockFile(file2, options),
|
|
12850
|
+
mtime,
|
|
12851
|
+
mtimePrecision: mtimePrecision2,
|
|
12852
|
+
options,
|
|
12853
|
+
lastUpdate: Date.now()
|
|
12854
|
+
};
|
|
12855
|
+
updateLock(file2, options);
|
|
12856
|
+
callback(null, (releasedCallback) => {
|
|
12857
|
+
if (lock2.released) {
|
|
12858
|
+
return releasedCallback && releasedCallback(Object.assign(new Error("Lock is already released"), { code: "ERELEASED" }));
|
|
12859
|
+
}
|
|
12860
|
+
unlock(file2, { ...options, realpath: false }, releasedCallback);
|
|
12861
|
+
});
|
|
12862
|
+
});
|
|
12863
|
+
});
|
|
12864
|
+
});
|
|
12865
|
+
}
|
|
12866
|
+
function unlock(file, options, callback) {
|
|
12867
|
+
options = {
|
|
12868
|
+
fs: fs12,
|
|
12869
|
+
realpath: true,
|
|
12870
|
+
...options
|
|
12871
|
+
};
|
|
12872
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
12873
|
+
if (err) {
|
|
12874
|
+
return callback(err);
|
|
12875
|
+
}
|
|
12876
|
+
const lock2 = locks[file2];
|
|
12877
|
+
if (!lock2) {
|
|
12878
|
+
return callback(Object.assign(new Error("Lock is not acquired/owned by you"), { code: "ENOTACQUIRED" }));
|
|
12879
|
+
}
|
|
12880
|
+
lock2.updateTimeout && clearTimeout(lock2.updateTimeout);
|
|
12881
|
+
lock2.released = true;
|
|
12882
|
+
delete locks[file2];
|
|
12883
|
+
removeLock(file2, options, callback);
|
|
12884
|
+
});
|
|
12885
|
+
}
|
|
12886
|
+
function check(file, options, callback) {
|
|
12887
|
+
options = {
|
|
12888
|
+
stale: 1e4,
|
|
12889
|
+
realpath: true,
|
|
12890
|
+
fs: fs12,
|
|
12891
|
+
...options
|
|
12892
|
+
};
|
|
12893
|
+
options.stale = Math.max(options.stale || 0, 2000);
|
|
12894
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
12895
|
+
if (err) {
|
|
12896
|
+
return callback(err);
|
|
12897
|
+
}
|
|
12898
|
+
options.fs.stat(getLockFile(file2, options), (err2, stat3) => {
|
|
12899
|
+
if (err2) {
|
|
12900
|
+
return err2.code === "ENOENT" ? callback(null, false) : callback(err2);
|
|
12901
|
+
}
|
|
12902
|
+
return callback(null, !isLockStale(stat3, options));
|
|
12903
|
+
});
|
|
12904
|
+
});
|
|
12905
|
+
}
|
|
12906
|
+
function getLocks() {
|
|
12907
|
+
return locks;
|
|
12908
|
+
}
|
|
12909
|
+
onExit2(() => {
|
|
12910
|
+
for (const file in locks) {
|
|
12911
|
+
const options = locks[file].options;
|
|
12912
|
+
try {
|
|
12913
|
+
options.fs.rmdirSync(getLockFile(file, options));
|
|
12914
|
+
} catch (e2) {}
|
|
12915
|
+
}
|
|
12916
|
+
});
|
|
12917
|
+
exports.lock = lock;
|
|
12918
|
+
exports.unlock = unlock;
|
|
12919
|
+
exports.check = check;
|
|
12920
|
+
exports.getLocks = getLocks;
|
|
12921
|
+
});
|
|
12922
|
+
|
|
12923
|
+
// node_modules/proper-lockfile/lib/adapter.js
|
|
12924
|
+
var require_adapter = __commonJS((exports, module) => {
|
|
12925
|
+
var fs12 = require_graceful_fs();
|
|
12926
|
+
function createSyncFs(fs13) {
|
|
12927
|
+
const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
|
|
12928
|
+
const newFs = { ...fs13 };
|
|
12929
|
+
methods.forEach((method) => {
|
|
12930
|
+
newFs[method] = (...args) => {
|
|
12931
|
+
const callback = args.pop();
|
|
12932
|
+
let ret;
|
|
12933
|
+
try {
|
|
12934
|
+
ret = fs13[`${method}Sync`](...args);
|
|
12935
|
+
} catch (err) {
|
|
12936
|
+
return callback(err);
|
|
12937
|
+
}
|
|
12938
|
+
callback(null, ret);
|
|
12939
|
+
};
|
|
12940
|
+
});
|
|
12941
|
+
return newFs;
|
|
12942
|
+
}
|
|
12943
|
+
function toPromise(method) {
|
|
12944
|
+
return (...args) => new Promise((resolve3, reject) => {
|
|
12945
|
+
args.push((err, result) => {
|
|
12946
|
+
if (err) {
|
|
12947
|
+
reject(err);
|
|
12948
|
+
} else {
|
|
12949
|
+
resolve3(result);
|
|
12950
|
+
}
|
|
12951
|
+
});
|
|
12952
|
+
method(...args);
|
|
12953
|
+
});
|
|
12954
|
+
}
|
|
12955
|
+
function toSync(method) {
|
|
12956
|
+
return (...args) => {
|
|
12957
|
+
let err;
|
|
12958
|
+
let result;
|
|
12959
|
+
args.push((_err, _result) => {
|
|
12960
|
+
err = _err;
|
|
12961
|
+
result = _result;
|
|
12962
|
+
});
|
|
12963
|
+
method(...args);
|
|
12964
|
+
if (err) {
|
|
12965
|
+
throw err;
|
|
12966
|
+
}
|
|
12967
|
+
return result;
|
|
12968
|
+
};
|
|
12969
|
+
}
|
|
12970
|
+
function toSyncOptions(options) {
|
|
12971
|
+
options = { ...options };
|
|
12972
|
+
options.fs = createSyncFs(options.fs || fs12);
|
|
12973
|
+
if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
|
|
12974
|
+
throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
|
|
12975
|
+
}
|
|
12976
|
+
return options;
|
|
12977
|
+
}
|
|
12978
|
+
module.exports = {
|
|
12979
|
+
toPromise,
|
|
12980
|
+
toSync,
|
|
12981
|
+
toSyncOptions
|
|
12982
|
+
};
|
|
12983
|
+
});
|
|
12984
|
+
|
|
12985
|
+
// node_modules/proper-lockfile/index.js
|
|
12986
|
+
var require_proper_lockfile = __commonJS((exports, module) => {
|
|
12987
|
+
var lockfile = require_lockfile();
|
|
12988
|
+
var { toPromise, toSync, toSyncOptions } = require_adapter();
|
|
12989
|
+
async function lock(file, options) {
|
|
12990
|
+
const release = await toPromise(lockfile.lock)(file, options);
|
|
12991
|
+
return toPromise(release);
|
|
12992
|
+
}
|
|
12993
|
+
function lockSync(file, options) {
|
|
12994
|
+
const release = toSync(lockfile.lock)(file, toSyncOptions(options));
|
|
12995
|
+
return toSync(release);
|
|
12996
|
+
}
|
|
12997
|
+
function unlock(file, options) {
|
|
12998
|
+
return toPromise(lockfile.unlock)(file, options);
|
|
12999
|
+
}
|
|
13000
|
+
function unlockSync(file, options) {
|
|
13001
|
+
return toSync(lockfile.unlock)(file, toSyncOptions(options));
|
|
13002
|
+
}
|
|
13003
|
+
function check(file, options) {
|
|
13004
|
+
return toPromise(lockfile.check)(file, options);
|
|
13005
|
+
}
|
|
13006
|
+
function checkSync(file, options) {
|
|
13007
|
+
return toSync(lockfile.check)(file, toSyncOptions(options));
|
|
13008
|
+
}
|
|
13009
|
+
module.exports = lock;
|
|
13010
|
+
module.exports.lock = lock;
|
|
13011
|
+
module.exports.unlock = unlock;
|
|
13012
|
+
module.exports.lockSync = lockSync;
|
|
13013
|
+
module.exports.unlockSync = unlockSync;
|
|
13014
|
+
module.exports.check = check;
|
|
13015
|
+
module.exports.checkSync = checkSync;
|
|
13016
|
+
});
|
|
13017
|
+
|
|
12256
13018
|
// src/services/package-installer/install-error-handler.ts
|
|
12257
13019
|
import { existsSync as existsSync6, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "node:fs";
|
|
12258
|
-
import { join as
|
|
13020
|
+
import { join as join25 } from "node:path";
|
|
12259
13021
|
function parseNameReason(str) {
|
|
12260
13022
|
const colonIndex = str.indexOf(":");
|
|
12261
13023
|
if (colonIndex === -1) {
|
|
@@ -12264,7 +13026,7 @@ function parseNameReason(str) {
|
|
|
12264
13026
|
return [str.slice(0, colonIndex).trim(), str.slice(colonIndex + 1).trim()];
|
|
12265
13027
|
}
|
|
12266
13028
|
function displayInstallErrors(skillsDir) {
|
|
12267
|
-
const summaryPath =
|
|
13029
|
+
const summaryPath = join25(skillsDir, ".install-error-summary.json");
|
|
12268
13030
|
if (!existsSync6(summaryPath)) {
|
|
12269
13031
|
logger.error("Skills installation failed. Run with --verbose for details.");
|
|
12270
13032
|
return;
|
|
@@ -12355,7 +13117,7 @@ async function checkNeedsSudoPackages() {
|
|
|
12355
13117
|
}
|
|
12356
13118
|
}
|
|
12357
13119
|
function hasInstallState(skillsDir) {
|
|
12358
|
-
const stateFilePath =
|
|
13120
|
+
const stateFilePath = join25(skillsDir, ".install-state.json");
|
|
12359
13121
|
return existsSync6(stateFilePath);
|
|
12360
13122
|
}
|
|
12361
13123
|
var WHICH_COMMAND_TIMEOUT_MS = 5000;
|
|
@@ -12368,19 +13130,20 @@ var exports_gemini_mcp_linker = {};
|
|
|
12368
13130
|
__export(exports_gemini_mcp_linker, {
|
|
12369
13131
|
processGeminiMcpLinking: () => processGeminiMcpLinking,
|
|
12370
13132
|
linkGeminiMcpConfig: () => linkGeminiMcpConfig,
|
|
13133
|
+
getGeminiSettingsPath: () => getGeminiSettingsPath,
|
|
12371
13134
|
findMcpConfigPath: () => findMcpConfigPath,
|
|
12372
13135
|
checkExistingGeminiConfig: () => checkExistingGeminiConfig,
|
|
12373
13136
|
addGeminiToGitignore: () => addGeminiToGitignore
|
|
12374
13137
|
});
|
|
12375
13138
|
import { existsSync as existsSync7, lstatSync, readlinkSync } from "node:fs";
|
|
12376
|
-
import { mkdir as mkdir9, readFile as
|
|
13139
|
+
import { mkdir as mkdir9, readFile as readFile15, symlink as symlink2, writeFile as writeFile13 } from "node:fs/promises";
|
|
12377
13140
|
import { homedir as homedir4 } from "node:os";
|
|
12378
|
-
import { dirname as dirname6, join as
|
|
13141
|
+
import { dirname as dirname6, join as join26, resolve as resolve3 } from "node:path";
|
|
12379
13142
|
function getGlobalMcpConfigPath() {
|
|
12380
|
-
return
|
|
13143
|
+
return join26(homedir4(), ".claude", ".mcp.json");
|
|
12381
13144
|
}
|
|
12382
13145
|
function getLocalMcpConfigPath(projectDir) {
|
|
12383
|
-
return
|
|
13146
|
+
return join26(projectDir, ".mcp.json");
|
|
12384
13147
|
}
|
|
12385
13148
|
function findMcpConfigPath(projectDir) {
|
|
12386
13149
|
const localPath = getLocalMcpConfigPath(projectDir);
|
|
@@ -12396,25 +13159,36 @@ function findMcpConfigPath(projectDir) {
|
|
|
12396
13159
|
logger.debug("No MCP config found (local or global)");
|
|
12397
13160
|
return null;
|
|
12398
13161
|
}
|
|
12399
|
-
function
|
|
12400
|
-
|
|
12401
|
-
|
|
12402
|
-
|
|
13162
|
+
function getGeminiSettingsPath(projectDir, isGlobal) {
|
|
13163
|
+
if (isGlobal) {
|
|
13164
|
+
return join26(homedir4(), ".gemini", "settings.json");
|
|
13165
|
+
}
|
|
13166
|
+
return join26(projectDir, ".gemini", "settings.json");
|
|
13167
|
+
}
|
|
13168
|
+
function checkExistingGeminiConfig(projectDir, isGlobal = false) {
|
|
13169
|
+
const geminiSettingsPath = getGeminiSettingsPath(projectDir, isGlobal);
|
|
13170
|
+
if (!existsSync7(geminiSettingsPath)) {
|
|
13171
|
+
return { exists: false, isSymlink: false, settingsPath: geminiSettingsPath };
|
|
12403
13172
|
}
|
|
12404
13173
|
try {
|
|
12405
13174
|
const stats = lstatSync(geminiSettingsPath);
|
|
12406
13175
|
if (stats.isSymbolicLink()) {
|
|
12407
13176
|
const target = readlinkSync(geminiSettingsPath);
|
|
12408
|
-
return {
|
|
13177
|
+
return {
|
|
13178
|
+
exists: true,
|
|
13179
|
+
isSymlink: true,
|
|
13180
|
+
currentTarget: target,
|
|
13181
|
+
settingsPath: geminiSettingsPath
|
|
13182
|
+
};
|
|
12409
13183
|
}
|
|
12410
|
-
return { exists: true, isSymlink: false };
|
|
13184
|
+
return { exists: true, isSymlink: false, settingsPath: geminiSettingsPath };
|
|
12411
13185
|
} catch {
|
|
12412
|
-
return { exists: true, isSymlink: false };
|
|
13186
|
+
return { exists: true, isSymlink: false, settingsPath: geminiSettingsPath };
|
|
12413
13187
|
}
|
|
12414
13188
|
}
|
|
12415
13189
|
async function readJsonFile(filePath) {
|
|
12416
13190
|
try {
|
|
12417
|
-
const content = await
|
|
13191
|
+
const content = await readFile15(filePath, "utf-8");
|
|
12418
13192
|
return JSON.parse(content);
|
|
12419
13193
|
} catch (error) {
|
|
12420
13194
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -12422,20 +13196,25 @@ async function readJsonFile(filePath) {
|
|
|
12422
13196
|
return null;
|
|
12423
13197
|
}
|
|
12424
13198
|
}
|
|
12425
|
-
async function createSymlink(targetPath, linkPath, projectDir) {
|
|
13199
|
+
async function createSymlink(targetPath, linkPath, projectDir, isGlobal) {
|
|
12426
13200
|
const isWindows5 = process.platform === "win32";
|
|
12427
13201
|
const linkDir = dirname6(linkPath);
|
|
12428
13202
|
if (!existsSync7(linkDir)) {
|
|
12429
13203
|
await mkdir9(linkDir, { recursive: true });
|
|
12430
13204
|
logger.debug(`Created directory: ${linkDir}`);
|
|
12431
13205
|
}
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
13206
|
+
let symlinkTarget;
|
|
13207
|
+
if (isGlobal) {
|
|
13208
|
+
symlinkTarget = getGlobalMcpConfigPath();
|
|
13209
|
+
} else {
|
|
13210
|
+
const localMcpPath = join26(projectDir, ".mcp.json");
|
|
13211
|
+
const isLocalConfig = targetPath === localMcpPath;
|
|
13212
|
+
symlinkTarget = isLocalConfig ? "../.mcp.json" : targetPath;
|
|
13213
|
+
}
|
|
12435
13214
|
try {
|
|
12436
13215
|
await symlink2(symlinkTarget, linkPath, isWindows5 ? "file" : undefined);
|
|
12437
13216
|
logger.debug(`Created symlink: ${linkPath} → ${symlinkTarget}`);
|
|
12438
|
-
return { success: true, method: "symlink", targetPath };
|
|
13217
|
+
return { success: true, method: "symlink", targetPath, geminiSettingsPath: linkPath };
|
|
12439
13218
|
} catch (error) {
|
|
12440
13219
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
12441
13220
|
return {
|
|
@@ -12461,7 +13240,7 @@ async function createNewSettingsWithMerge(geminiSettingsPath, mcpConfigPath) {
|
|
|
12461
13240
|
}
|
|
12462
13241
|
const newSettings = { mcpServers };
|
|
12463
13242
|
try {
|
|
12464
|
-
await
|
|
13243
|
+
await writeFile13(geminiSettingsPath, JSON.stringify(newSettings, null, 2), "utf-8");
|
|
12465
13244
|
logger.debug(`Created new Gemini settings with mcpServers: ${geminiSettingsPath}`);
|
|
12466
13245
|
return { success: true, method: "merge", targetPath: mcpConfigPath };
|
|
12467
13246
|
} catch (error) {
|
|
@@ -12491,7 +13270,7 @@ async function mergeGeminiSettings(geminiSettingsPath, mcpConfigPath) {
|
|
|
12491
13270
|
mcpServers
|
|
12492
13271
|
};
|
|
12493
13272
|
try {
|
|
12494
|
-
await
|
|
13273
|
+
await writeFile13(geminiSettingsPath, JSON.stringify(mergedSettings, null, 2), "utf-8");
|
|
12495
13274
|
logger.debug(`Merged mcpServers into: ${geminiSettingsPath}`);
|
|
12496
13275
|
return { success: true, method: "merge", targetPath: mcpConfigPath };
|
|
12497
13276
|
} catch (error) {
|
|
@@ -12504,12 +13283,12 @@ async function mergeGeminiSettings(geminiSettingsPath, mcpConfigPath) {
|
|
|
12504
13283
|
}
|
|
12505
13284
|
}
|
|
12506
13285
|
async function addGeminiToGitignore(projectDir) {
|
|
12507
|
-
const gitignorePath =
|
|
13286
|
+
const gitignorePath = join26(projectDir, ".gitignore");
|
|
12508
13287
|
const geminiPattern = ".gemini/";
|
|
12509
13288
|
try {
|
|
12510
13289
|
let content = "";
|
|
12511
13290
|
if (existsSync7(gitignorePath)) {
|
|
12512
|
-
content = await
|
|
13291
|
+
content = await readFile15(gitignorePath, "utf-8");
|
|
12513
13292
|
const lines = content.split(`
|
|
12514
13293
|
`).map((line) => line.trim()).filter((line) => !line.startsWith("#"));
|
|
12515
13294
|
const geminiPatterns = [".gemini/", ".gemini", "/.gemini/", "/.gemini"];
|
|
@@ -12522,7 +13301,7 @@ async function addGeminiToGitignore(projectDir) {
|
|
|
12522
13301
|
`) || content === "" ? "" : `
|
|
12523
13302
|
`;
|
|
12524
13303
|
const comment = "# Gemini CLI settings (contains user-specific config)";
|
|
12525
|
-
await
|
|
13304
|
+
await writeFile13(gitignorePath, `${content}${newLine}${comment}
|
|
12526
13305
|
${geminiPattern}
|
|
12527
13306
|
`, "utf-8");
|
|
12528
13307
|
logger.debug(`Added ${geminiPattern} to .gitignore`);
|
|
@@ -12532,9 +13311,9 @@ ${geminiPattern}
|
|
|
12532
13311
|
}
|
|
12533
13312
|
}
|
|
12534
13313
|
async function linkGeminiMcpConfig(projectDir, options = {}) {
|
|
12535
|
-
const { skipGitignore = false } = options;
|
|
13314
|
+
const { skipGitignore = false, isGlobal = false } = options;
|
|
12536
13315
|
const resolvedProjectDir = resolve3(projectDir);
|
|
12537
|
-
const geminiSettingsPath =
|
|
13316
|
+
const geminiSettingsPath = getGeminiSettingsPath(resolvedProjectDir, isGlobal);
|
|
12538
13317
|
const mcpConfigPath = findMcpConfigPath(resolvedProjectDir);
|
|
12539
13318
|
if (!mcpConfigPath) {
|
|
12540
13319
|
return {
|
|
@@ -12543,32 +13322,38 @@ async function linkGeminiMcpConfig(projectDir, options = {}) {
|
|
|
12543
13322
|
error: "No MCP config found. Create .mcp.json or ~/.claude/.mcp.json first."
|
|
12544
13323
|
};
|
|
12545
13324
|
}
|
|
12546
|
-
const existing = checkExistingGeminiConfig(resolvedProjectDir);
|
|
13325
|
+
const existing = checkExistingGeminiConfig(resolvedProjectDir, isGlobal);
|
|
12547
13326
|
let result;
|
|
12548
13327
|
if (!existing.exists) {
|
|
12549
|
-
result = await createSymlink(mcpConfigPath, geminiSettingsPath, resolvedProjectDir);
|
|
13328
|
+
result = await createSymlink(mcpConfigPath, geminiSettingsPath, resolvedProjectDir, isGlobal);
|
|
12550
13329
|
if (!result.success && process.platform === "win32") {
|
|
12551
13330
|
logger.debug("Symlink failed on Windows, falling back to creating new settings with mcpServers");
|
|
12552
13331
|
result = await createNewSettingsWithMerge(geminiSettingsPath, mcpConfigPath);
|
|
12553
13332
|
}
|
|
12554
13333
|
} else if (existing.isSymlink) {
|
|
12555
13334
|
logger.debug(`Gemini config already symlinked: ${existing.currentTarget}`);
|
|
12556
|
-
result = {
|
|
13335
|
+
result = {
|
|
13336
|
+
success: true,
|
|
13337
|
+
method: "skipped",
|
|
13338
|
+
targetPath: existing.currentTarget,
|
|
13339
|
+
geminiSettingsPath
|
|
13340
|
+
};
|
|
12557
13341
|
} else {
|
|
12558
13342
|
result = await mergeGeminiSettings(geminiSettingsPath, mcpConfigPath);
|
|
12559
13343
|
}
|
|
12560
|
-
if (result.success && !skipGitignore) {
|
|
13344
|
+
if (result.success && !skipGitignore && !isGlobal) {
|
|
12561
13345
|
await addGeminiToGitignore(resolvedProjectDir);
|
|
12562
13346
|
}
|
|
12563
13347
|
return result;
|
|
12564
13348
|
}
|
|
12565
|
-
async function processGeminiMcpLinking(projectDir) {
|
|
13349
|
+
async function processGeminiMcpLinking(projectDir, options = {}) {
|
|
12566
13350
|
logger.info("Setting up Gemini CLI MCP integration...");
|
|
12567
|
-
const result = await linkGeminiMcpConfig(projectDir);
|
|
13351
|
+
const result = await linkGeminiMcpConfig(projectDir, options);
|
|
13352
|
+
const settingsPath = result.geminiSettingsPath || (options.isGlobal ? "~/.gemini/settings.json" : ".gemini/settings.json");
|
|
12568
13353
|
if (result.success) {
|
|
12569
13354
|
switch (result.method) {
|
|
12570
13355
|
case "symlink":
|
|
12571
|
-
logger.success(`Gemini MCP linked:
|
|
13356
|
+
logger.success(`Gemini MCP linked: ${settingsPath} → ${result.targetPath}`);
|
|
12572
13357
|
logger.info("MCP servers will auto-sync with your Claude config.");
|
|
12573
13358
|
break;
|
|
12574
13359
|
case "merge":
|
|
@@ -12581,7 +13366,11 @@ async function processGeminiMcpLinking(projectDir) {
|
|
|
12581
13366
|
}
|
|
12582
13367
|
} else {
|
|
12583
13368
|
logger.warning(`Gemini MCP setup incomplete: ${result.error}`);
|
|
12584
|
-
|
|
13369
|
+
if (options.isGlobal) {
|
|
13370
|
+
logger.info("Manual setup: mkdir -p ~/.gemini && ln -sf ~/.claude/.mcp.json ~/.gemini/settings.json");
|
|
13371
|
+
} else {
|
|
13372
|
+
logger.info("Manual setup: mkdir -p .gemini && ln -sf ../.mcp.json .gemini/settings.json");
|
|
13373
|
+
}
|
|
12585
13374
|
}
|
|
12586
13375
|
}
|
|
12587
13376
|
var init_gemini_mcp_linker = __esm(() => {
|
|
@@ -12604,7 +13393,7 @@ __export(exports_package_installer, {
|
|
|
12604
13393
|
getPackageVersion: () => getPackageVersion
|
|
12605
13394
|
});
|
|
12606
13395
|
import { exec as exec5, execFile as execFile2, spawn } from "node:child_process";
|
|
12607
|
-
import { join as
|
|
13396
|
+
import { join as join27, resolve as resolve4 } from "node:path";
|
|
12608
13397
|
import { promisify as promisify5 } from "node:util";
|
|
12609
13398
|
function executeInteractiveScript(command, args, options) {
|
|
12610
13399
|
return new Promise((resolve5, reject) => {
|
|
@@ -12671,7 +13460,7 @@ async function isGeminiInstalled() {
|
|
|
12671
13460
|
}
|
|
12672
13461
|
async function isPackageInstalled(packageName) {
|
|
12673
13462
|
validatePackageName(packageName);
|
|
12674
|
-
if (
|
|
13463
|
+
if (isCIEnvironment()) {
|
|
12675
13464
|
logger.info(`CI environment detected: skipping network check for ${packageName}`);
|
|
12676
13465
|
return false;
|
|
12677
13466
|
}
|
|
@@ -12707,7 +13496,7 @@ async function isPackageInstalled(packageName) {
|
|
|
12707
13496
|
}
|
|
12708
13497
|
async function getPackageVersion(packageName) {
|
|
12709
13498
|
validatePackageName(packageName);
|
|
12710
|
-
if (
|
|
13499
|
+
if (isCIEnvironment()) {
|
|
12711
13500
|
logger.info(`CI environment detected: skipping version check for ${packageName}`);
|
|
12712
13501
|
return null;
|
|
12713
13502
|
}
|
|
@@ -12787,7 +13576,7 @@ async function installPackageGlobally(packageName, packageDisplayName) {
|
|
|
12787
13576
|
}
|
|
12788
13577
|
async function installOpenCode() {
|
|
12789
13578
|
const displayName = "OpenCode CLI";
|
|
12790
|
-
if (
|
|
13579
|
+
if (isCIEnvironment()) {
|
|
12791
13580
|
logger.info("CI environment detected: skipping OpenCode installation");
|
|
12792
13581
|
return {
|
|
12793
13582
|
success: false,
|
|
@@ -12799,7 +13588,7 @@ async function installOpenCode() {
|
|
|
12799
13588
|
logger.info(`Installing ${displayName}...`);
|
|
12800
13589
|
const { unlink: unlink5 } = await import("node:fs/promises");
|
|
12801
13590
|
const { tmpdir: tmpdir3 } = await import("node:os");
|
|
12802
|
-
const tempScriptPath =
|
|
13591
|
+
const tempScriptPath = join27(tmpdir3(), "opencode-install.sh");
|
|
12803
13592
|
try {
|
|
12804
13593
|
logger.info("Downloading OpenCode installation script...");
|
|
12805
13594
|
await execFileAsync("curl", ["-fsSL", "https://opencode.ai/install", "-o", tempScriptPath], {
|
|
@@ -12896,7 +13685,7 @@ function validateScriptPath(skillsDir, scriptPath) {
|
|
|
12896
13685
|
}
|
|
12897
13686
|
async function installSkillsDependencies(skillsDir) {
|
|
12898
13687
|
const displayName = "Skills Dependencies";
|
|
12899
|
-
if (
|
|
13688
|
+
if (isCIEnvironment()) {
|
|
12900
13689
|
logger.info("CI environment detected: skipping skills installation");
|
|
12901
13690
|
return {
|
|
12902
13691
|
success: false,
|
|
@@ -12918,7 +13707,7 @@ async function installSkillsDependencies(skillsDir) {
|
|
|
12918
13707
|
const clack = await Promise.resolve().then(() => (init_dist2(), exports_dist));
|
|
12919
13708
|
const platform9 = process.platform;
|
|
12920
13709
|
const scriptName = platform9 === "win32" ? "install.ps1" : "install.sh";
|
|
12921
|
-
const scriptPath =
|
|
13710
|
+
const scriptPath = join27(skillsDir, scriptName);
|
|
12922
13711
|
try {
|
|
12923
13712
|
validateScriptPath(skillsDir, scriptPath);
|
|
12924
13713
|
} catch (error) {
|
|
@@ -12934,7 +13723,7 @@ async function installSkillsDependencies(skillsDir) {
|
|
|
12934
13723
|
logger.warning(`Skills installation script not found: ${scriptPath}`);
|
|
12935
13724
|
logger.info("");
|
|
12936
13725
|
logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
|
|
12937
|
-
logger.info(` See: ${
|
|
13726
|
+
logger.info(` See: ${join27(skillsDir, "INSTALLATION.md")}`);
|
|
12938
13727
|
logger.info("");
|
|
12939
13728
|
logger.info("Quick start:");
|
|
12940
13729
|
logger.info(" cd .claude/skills/ai-multimodal/scripts");
|
|
@@ -12950,8 +13739,8 @@ async function installSkillsDependencies(skillsDir) {
|
|
|
12950
13739
|
logger.info(` Platform: ${platform9 === "win32" ? "Windows (PowerShell)" : "Unix (bash)"}`);
|
|
12951
13740
|
if (logger.isVerbose()) {
|
|
12952
13741
|
try {
|
|
12953
|
-
const { readFile:
|
|
12954
|
-
const scriptContent = await
|
|
13742
|
+
const { readFile: readFile16 } = await import("node:fs/promises");
|
|
13743
|
+
const scriptContent = await readFile16(scriptPath, "utf-8");
|
|
12955
13744
|
const previewLines = scriptContent.split(`
|
|
12956
13745
|
`).slice(0, 20);
|
|
12957
13746
|
logger.verbose("Script preview (first 20 lines):");
|
|
@@ -12977,7 +13766,7 @@ async function installSkillsDependencies(skillsDir) {
|
|
|
12977
13766
|
logger.info(` ${platform9 === "win32" ? `powershell -File "${scriptPath}"` : `bash ${scriptPath}`}`);
|
|
12978
13767
|
logger.info("");
|
|
12979
13768
|
logger.info("Or see complete guide:");
|
|
12980
|
-
logger.info(` ${
|
|
13769
|
+
logger.info(` ${join27(skillsDir, "INSTALLATION.md")}`);
|
|
12981
13770
|
return {
|
|
12982
13771
|
success: false,
|
|
12983
13772
|
package: displayName,
|
|
@@ -13078,7 +13867,7 @@ async function installSkillsDependencies(skillsDir) {
|
|
|
13078
13867
|
logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
|
|
13079
13868
|
logger.info("");
|
|
13080
13869
|
logger.info("See complete guide:");
|
|
13081
|
-
logger.info(` cat ${
|
|
13870
|
+
logger.info(` cat ${join27(skillsDir, "INSTALLATION.md")}`);
|
|
13082
13871
|
logger.info("");
|
|
13083
13872
|
logger.info("Quick start:");
|
|
13084
13873
|
logger.info(" cd .claude/skills/ai-multimodal/scripts");
|
|
@@ -14072,7 +14861,7 @@ var init_help_interceptor = __esm(() => {
|
|
|
14072
14861
|
|
|
14073
14862
|
// src/index.ts
|
|
14074
14863
|
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
14075
|
-
import { join as
|
|
14864
|
+
import { join as join37 } from "path";
|
|
14076
14865
|
|
|
14077
14866
|
// node_modules/cac/dist/index.mjs
|
|
14078
14867
|
import { EventEmitter } from "events";
|
|
@@ -14677,7 +15466,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
14677
15466
|
// package.json
|
|
14678
15467
|
var package_default = {
|
|
14679
15468
|
name: "claudekit-cli",
|
|
14680
|
-
version: "3.
|
|
15469
|
+
version: "3.11.0",
|
|
14681
15470
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
14682
15471
|
type: "module",
|
|
14683
15472
|
repository: {
|
|
@@ -14697,7 +15486,7 @@ var package_default = {
|
|
|
14697
15486
|
],
|
|
14698
15487
|
scripts: {
|
|
14699
15488
|
dev: "bun run src/index.ts",
|
|
14700
|
-
build: "bun build src/index.ts --outdir dist --target node --external
|
|
15489
|
+
build: "bun build src/index.ts --outdir dist --target node --external @octokit/rest",
|
|
14701
15490
|
compile: "bun build src/index.ts --compile --outfile ck",
|
|
14702
15491
|
"compile:binary": "bun build src/index.ts --compile --outfile bin/ck",
|
|
14703
15492
|
"compile:binaries": "node scripts/build-all-binaries.js",
|
|
@@ -14738,11 +15527,11 @@ var package_default = {
|
|
|
14738
15527
|
"extract-zip": "^2.0.1",
|
|
14739
15528
|
"fs-extra": "^11.2.0",
|
|
14740
15529
|
ignore: "^5.3.2",
|
|
14741
|
-
keytar: "^7.9.0",
|
|
14742
15530
|
minimatch: "^10.1.1",
|
|
14743
15531
|
ora: "^8.0.0",
|
|
14744
15532
|
"p-limit": "^7.2.0",
|
|
14745
15533
|
picocolors: "^1.1.1",
|
|
15534
|
+
"proper-lockfile": "^4.1.2",
|
|
14746
15535
|
tar: "^7.4.3",
|
|
14747
15536
|
tmp: "^0.2.3",
|
|
14748
15537
|
zod: "^3.23.8"
|
|
@@ -14755,6 +15544,7 @@ var package_default = {
|
|
|
14755
15544
|
"@types/cli-progress": "^3.11.6",
|
|
14756
15545
|
"@types/fs-extra": "^11.0.4",
|
|
14757
15546
|
"@types/node": "^22.10.1",
|
|
15547
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
14758
15548
|
"@types/tar": "^6.1.13",
|
|
14759
15549
|
"@types/tmp": "^0.2.6",
|
|
14760
15550
|
"semantic-release": "^24.2.0",
|
|
@@ -14922,7 +15712,12 @@ init_logger();
|
|
|
14922
15712
|
import { exec } from "node:child_process";
|
|
14923
15713
|
import { promisify } from "node:util";
|
|
14924
15714
|
var execAsync = promisify(exec);
|
|
14925
|
-
|
|
15715
|
+
function shouldSkipExpensiveOperations() {
|
|
15716
|
+
if (process.env.CK_TEST_HOME) {
|
|
15717
|
+
return false;
|
|
15718
|
+
}
|
|
15719
|
+
return process.env.CI === "true" || process.env.CI_SAFE_MODE === "true";
|
|
15720
|
+
}
|
|
14926
15721
|
function getOSInfo() {
|
|
14927
15722
|
const platform = process.platform;
|
|
14928
15723
|
const arch = process.arch;
|
|
@@ -14994,7 +15789,7 @@ var DEPENDENCIES = {
|
|
|
14994
15789
|
}
|
|
14995
15790
|
};
|
|
14996
15791
|
async function commandExists(command) {
|
|
14997
|
-
if (
|
|
15792
|
+
if (shouldSkipExpensiveOperations()) {
|
|
14998
15793
|
const supportedCommands = ["node", "python", "python3", "pip", "pip3", "claude"];
|
|
14999
15794
|
return supportedCommands.includes(command);
|
|
15000
15795
|
}
|
|
@@ -15010,7 +15805,7 @@ async function commandExists(command) {
|
|
|
15010
15805
|
}
|
|
15011
15806
|
}
|
|
15012
15807
|
async function getCommandPath(command) {
|
|
15013
|
-
if (
|
|
15808
|
+
if (shouldSkipExpensiveOperations()) {
|
|
15014
15809
|
const ciPath = getCICommandPath(command);
|
|
15015
15810
|
if (ciPath)
|
|
15016
15811
|
return ciPath;
|
|
@@ -15029,7 +15824,7 @@ async function getCommandPath(command) {
|
|
|
15029
15824
|
}
|
|
15030
15825
|
}
|
|
15031
15826
|
async function getCommandVersion(command, versionFlag, versionRegex) {
|
|
15032
|
-
if (
|
|
15827
|
+
if (shouldSkipExpensiveOperations()) {
|
|
15033
15828
|
const mockVersions = {
|
|
15034
15829
|
npm: "10.0.0",
|
|
15035
15830
|
node: "20.0.0",
|
|
@@ -15361,6 +16156,12 @@ function compareVersions2(a, b) {
|
|
|
15361
16156
|
}
|
|
15362
16157
|
return 0;
|
|
15363
16158
|
}
|
|
16159
|
+
function shouldSkipExpensiveOperations2() {
|
|
16160
|
+
if (process.env.CK_TEST_HOME) {
|
|
16161
|
+
return false;
|
|
16162
|
+
}
|
|
16163
|
+
return process.env.CI === "true" || process.env.CI_SAFE_MODE === "true";
|
|
16164
|
+
}
|
|
15364
16165
|
|
|
15365
16166
|
class SystemChecker {
|
|
15366
16167
|
group = "system";
|
|
@@ -15375,13 +16176,29 @@ class SystemChecker {
|
|
|
15375
16176
|
logger.verbose(`SystemChecker: Processing ${dep.name}`);
|
|
15376
16177
|
results.push(await this.mapDependencyToCheck(dep));
|
|
15377
16178
|
}
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
16179
|
+
if (!shouldSkipExpensiveOperations2()) {
|
|
16180
|
+
logger.verbose("SystemChecker: Checking git");
|
|
16181
|
+
results.push(await this.checkGit());
|
|
16182
|
+
logger.verbose("SystemChecker: Checking GitHub CLI");
|
|
16183
|
+
results.push(await this.checkGitHubCli());
|
|
16184
|
+
} else {
|
|
16185
|
+
logger.verbose("SystemChecker: Skipping git/gh checks in CI");
|
|
16186
|
+
results.push(this.createCISkipResult("git-version", "Git"));
|
|
16187
|
+
results.push(this.createCISkipResult("gh-cli-version", "GitHub CLI"));
|
|
16188
|
+
}
|
|
15382
16189
|
logger.verbose("SystemChecker: All system checks complete");
|
|
15383
16190
|
return results;
|
|
15384
16191
|
}
|
|
16192
|
+
createCISkipResult(id, name) {
|
|
16193
|
+
return {
|
|
16194
|
+
id,
|
|
16195
|
+
name,
|
|
16196
|
+
group: "system",
|
|
16197
|
+
status: "pass",
|
|
16198
|
+
message: "Skipped in CI",
|
|
16199
|
+
autoFixable: false
|
|
16200
|
+
};
|
|
16201
|
+
}
|
|
15385
16202
|
async mapDependencyToCheck(dep) {
|
|
15386
16203
|
const isInstalled = dep.installed && dep.meetsRequirements;
|
|
15387
16204
|
const name = this.formatDependencyName(dep.name);
|
|
@@ -16069,6 +16886,12 @@ async function getClaudeKitSetup(projectDir = process.cwd()) {
|
|
|
16069
16886
|
// src/domains/health-checks/claudekit-checker.ts
|
|
16070
16887
|
init_logger();
|
|
16071
16888
|
var HOOK_EXTENSIONS = [".js", ".cjs", ".mjs", ".ts", ".sh", ".ps1"];
|
|
16889
|
+
function shouldSkipExpensiveOperations3() {
|
|
16890
|
+
if (process.env.CK_TEST_HOME) {
|
|
16891
|
+
return false;
|
|
16892
|
+
}
|
|
16893
|
+
return process.env.CI === "true" || process.env.CI_SAFE_MODE === "true";
|
|
16894
|
+
}
|
|
16072
16895
|
|
|
16073
16896
|
class ClaudekitChecker {
|
|
16074
16897
|
group = "claudekit";
|
|
@@ -16338,6 +17161,18 @@ class ClaudekitChecker {
|
|
|
16338
17161
|
}
|
|
16339
17162
|
async checkGlobalDirReadable() {
|
|
16340
17163
|
const globalDir = PathResolver.getGlobalKitDir();
|
|
17164
|
+
if (shouldSkipExpensiveOperations3()) {
|
|
17165
|
+
return {
|
|
17166
|
+
id: "ck-global-dir-readable",
|
|
17167
|
+
name: "Global Dir Readable",
|
|
17168
|
+
group: "claudekit",
|
|
17169
|
+
priority: "standard",
|
|
17170
|
+
status: "info",
|
|
17171
|
+
message: "Skipped in CI/test environment",
|
|
17172
|
+
details: globalDir,
|
|
17173
|
+
autoFixable: false
|
|
17174
|
+
};
|
|
17175
|
+
}
|
|
16341
17176
|
try {
|
|
16342
17177
|
await access(globalDir, constants.R_OK);
|
|
16343
17178
|
return {
|
|
@@ -16366,6 +17201,18 @@ class ClaudekitChecker {
|
|
|
16366
17201
|
}
|
|
16367
17202
|
async checkGlobalDirWritable() {
|
|
16368
17203
|
const globalDir = PathResolver.getGlobalKitDir();
|
|
17204
|
+
if (shouldSkipExpensiveOperations3()) {
|
|
17205
|
+
return {
|
|
17206
|
+
id: "ck-global-dir-writable",
|
|
17207
|
+
name: "Global Dir Writable",
|
|
17208
|
+
group: "claudekit",
|
|
17209
|
+
priority: "standard",
|
|
17210
|
+
status: "info",
|
|
17211
|
+
message: "Skipped in CI/test environment",
|
|
17212
|
+
details: globalDir,
|
|
17213
|
+
autoFixable: false
|
|
17214
|
+
};
|
|
17215
|
+
}
|
|
16369
17216
|
const timestamp = Date.now();
|
|
16370
17217
|
const random = Math.random().toString(36).substring(2);
|
|
16371
17218
|
const testFile = join4(globalDir, `.ck-write-test-${timestamp}-${random}`);
|
|
@@ -17449,7 +18296,12 @@ Need help? Run with: ck new --verbose`, 404);
|
|
|
17449
18296
|
// src/domains/health-checks/auth-checker.ts
|
|
17450
18297
|
init_logger();
|
|
17451
18298
|
init_types2();
|
|
17452
|
-
|
|
18299
|
+
function shouldSkipExpensiveOperations4() {
|
|
18300
|
+
if (process.env.CK_TEST_HOME) {
|
|
18301
|
+
return false;
|
|
18302
|
+
}
|
|
18303
|
+
return process.env.CI === "true" || process.env.CI_SAFE_MODE === "true";
|
|
18304
|
+
}
|
|
17453
18305
|
|
|
17454
18306
|
class AuthChecker {
|
|
17455
18307
|
group = "auth";
|
|
@@ -17533,14 +18385,14 @@ class AuthChecker {
|
|
|
17533
18385
|
}
|
|
17534
18386
|
async checkRepoAccess(kit) {
|
|
17535
18387
|
const kitConfig = AVAILABLE_KITS[kit];
|
|
17536
|
-
if (
|
|
17537
|
-
logger.verbose(`AuthChecker: Skipping repo access check for ${kit} in CI`);
|
|
18388
|
+
if (shouldSkipExpensiveOperations4()) {
|
|
18389
|
+
logger.verbose(`AuthChecker: Skipping repo access check for ${kit} in CI/test`);
|
|
17538
18390
|
return {
|
|
17539
18391
|
id: `repo-access-${kit}`,
|
|
17540
18392
|
name: `Repository Access (${kit})`,
|
|
17541
18393
|
group: "auth",
|
|
17542
18394
|
status: "info",
|
|
17543
|
-
message: "Skipped in CI environment",
|
|
18395
|
+
message: "Skipped in CI/test environment",
|
|
17544
18396
|
autoFixable: false
|
|
17545
18397
|
};
|
|
17546
18398
|
}
|
|
@@ -17600,6 +18452,12 @@ import { constants as constants2, access as access2, mkdir as mkdir3, readFile a
|
|
|
17600
18452
|
import { arch, homedir as homedir3, platform as platform3 } from "node:os";
|
|
17601
18453
|
import { join as join6, normalize as normalize3 } from "node:path";
|
|
17602
18454
|
var IS_WINDOWS = platform3() === "win32";
|
|
18455
|
+
function shouldSkipExpensiveOperations5() {
|
|
18456
|
+
if (process.env.CK_TEST_HOME) {
|
|
18457
|
+
return false;
|
|
18458
|
+
}
|
|
18459
|
+
return process.env.CI === "true" || process.env.CI_SAFE_MODE === "true";
|
|
18460
|
+
}
|
|
17603
18461
|
|
|
17604
18462
|
class PlatformChecker {
|
|
17605
18463
|
group = "platform";
|
|
@@ -17698,6 +18556,18 @@ class PlatformChecker {
|
|
|
17698
18556
|
}
|
|
17699
18557
|
async checkGlobalDirAccess() {
|
|
17700
18558
|
const globalDir = PathResolver.getGlobalKitDir();
|
|
18559
|
+
if (shouldSkipExpensiveOperations5()) {
|
|
18560
|
+
return {
|
|
18561
|
+
id: "global-dir-access",
|
|
18562
|
+
name: "Global Dir Access",
|
|
18563
|
+
group: "platform",
|
|
18564
|
+
priority: "critical",
|
|
18565
|
+
status: "info",
|
|
18566
|
+
message: "Skipped in CI/test environment",
|
|
18567
|
+
details: globalDir,
|
|
18568
|
+
autoFixable: false
|
|
18569
|
+
};
|
|
18570
|
+
}
|
|
17701
18571
|
const testFile = join6(globalDir, ".ck-doctor-access-test");
|
|
17702
18572
|
try {
|
|
17703
18573
|
await mkdir3(globalDir, { recursive: true });
|
|
@@ -17771,6 +18641,17 @@ class PlatformChecker {
|
|
|
17771
18641
|
};
|
|
17772
18642
|
}
|
|
17773
18643
|
async checkLongPathSupport() {
|
|
18644
|
+
if (shouldSkipExpensiveOperations5()) {
|
|
18645
|
+
return {
|
|
18646
|
+
id: "long-path-support",
|
|
18647
|
+
name: "Long Path Support",
|
|
18648
|
+
group: "platform",
|
|
18649
|
+
priority: "extended",
|
|
18650
|
+
status: "info",
|
|
18651
|
+
message: "Skipped in CI/test environment",
|
|
18652
|
+
autoFixable: false
|
|
18653
|
+
};
|
|
18654
|
+
}
|
|
17774
18655
|
try {
|
|
17775
18656
|
const { execSync: execSync3 } = await import("node:child_process");
|
|
17776
18657
|
const result = execSync3('reg query "HKLM\\SYSTEM\\CurrentControlSet\\Control\\FileSystem" /v LongPathsEnabled', { encoding: "utf-8", timeout: 2000 });
|
|
@@ -17798,6 +18679,17 @@ class PlatformChecker {
|
|
|
17798
18679
|
}
|
|
17799
18680
|
}
|
|
17800
18681
|
async checkSymlinkSupport() {
|
|
18682
|
+
if (shouldSkipExpensiveOperations5()) {
|
|
18683
|
+
return {
|
|
18684
|
+
id: "symlink-support",
|
|
18685
|
+
name: "Symlink Support",
|
|
18686
|
+
group: "platform",
|
|
18687
|
+
priority: "extended",
|
|
18688
|
+
status: "info",
|
|
18689
|
+
message: "Skipped in CI/test environment",
|
|
18690
|
+
autoFixable: false
|
|
18691
|
+
};
|
|
18692
|
+
}
|
|
17801
18693
|
const testDir = PathResolver.getGlobalKitDir();
|
|
17802
18694
|
const target = join6(testDir, ".ck-symlink-test-target");
|
|
17803
18695
|
const link = join6(testDir, ".ck-symlink-test-link");
|
|
@@ -18521,7 +19413,7 @@ async function doctorCommand(options = {}) {
|
|
|
18521
19413
|
}
|
|
18522
19414
|
|
|
18523
19415
|
// src/commands/init.ts
|
|
18524
|
-
import { join as
|
|
19416
|
+
import { join as join32, resolve as resolve6 } from "node:path";
|
|
18525
19417
|
|
|
18526
19418
|
// src/domains/config/config-manager.ts
|
|
18527
19419
|
init_logger();
|
|
@@ -27518,7 +28410,7 @@ Solutions:
|
|
|
27518
28410
|
}
|
|
27519
28411
|
|
|
27520
28412
|
// src/domains/installation/file-merger.ts
|
|
27521
|
-
import { dirname as dirname5, join as join12, relative as
|
|
28413
|
+
import { dirname as dirname5, join as join12, relative as relative3 } from "node:path";
|
|
27522
28414
|
|
|
27523
28415
|
// src/domains/config/settings-merger.ts
|
|
27524
28416
|
init_logger();
|
|
@@ -29164,6 +30056,129 @@ minimatch.Minimatch = Minimatch;
|
|
|
29164
30056
|
minimatch.escape = escape;
|
|
29165
30057
|
minimatch.unescape = unescape;
|
|
29166
30058
|
|
|
30059
|
+
// src/domains/installation/selective-merger.ts
|
|
30060
|
+
import { stat as stat2 } from "node:fs/promises";
|
|
30061
|
+
|
|
30062
|
+
// src/services/file-operations/ownership-checker.ts
|
|
30063
|
+
import { createHash } from "node:crypto";
|
|
30064
|
+
import { createReadStream } from "node:fs";
|
|
30065
|
+
import { stat } from "node:fs/promises";
|
|
30066
|
+
import { relative as relative2 } from "node:path";
|
|
30067
|
+
|
|
30068
|
+
class OwnershipChecker {
|
|
30069
|
+
static async calculateChecksum(filePath) {
|
|
30070
|
+
return new Promise((resolve3, reject) => {
|
|
30071
|
+
const hash = createHash("sha256");
|
|
30072
|
+
const stream = createReadStream(filePath);
|
|
30073
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
30074
|
+
stream.on("end", () => {
|
|
30075
|
+
resolve3(hash.digest("hex"));
|
|
30076
|
+
});
|
|
30077
|
+
stream.on("error", (err) => {
|
|
30078
|
+
stream.destroy();
|
|
30079
|
+
reject(new Error(`Failed to calculate checksum for "${filePath}": ${err.message}`));
|
|
30080
|
+
});
|
|
30081
|
+
});
|
|
30082
|
+
}
|
|
30083
|
+
static async checkOwnership(filePath, metadata, claudeDir) {
|
|
30084
|
+
try {
|
|
30085
|
+
await stat(filePath);
|
|
30086
|
+
} catch {
|
|
30087
|
+
return { path: filePath, ownership: "user", exists: false };
|
|
30088
|
+
}
|
|
30089
|
+
if (!metadata || !metadata.files || metadata.files.length === 0) {
|
|
30090
|
+
return { path: filePath, ownership: "user", exists: true };
|
|
30091
|
+
}
|
|
30092
|
+
const relativePath = relative2(claudeDir, filePath).replace(/\\/g, "/");
|
|
30093
|
+
const tracked = metadata.files.find((f3) => f3.path === relativePath);
|
|
30094
|
+
if (!tracked) {
|
|
30095
|
+
return { path: filePath, ownership: "user", exists: true };
|
|
30096
|
+
}
|
|
30097
|
+
const actualChecksum = await OwnershipChecker.calculateChecksum(filePath);
|
|
30098
|
+
if (actualChecksum === tracked.checksum) {
|
|
30099
|
+
return {
|
|
30100
|
+
path: filePath,
|
|
30101
|
+
ownership: "ck",
|
|
30102
|
+
expectedChecksum: tracked.checksum,
|
|
30103
|
+
actualChecksum,
|
|
30104
|
+
exists: true
|
|
30105
|
+
};
|
|
30106
|
+
}
|
|
30107
|
+
return {
|
|
30108
|
+
path: filePath,
|
|
30109
|
+
ownership: "ck-modified",
|
|
30110
|
+
expectedChecksum: tracked.checksum,
|
|
30111
|
+
actualChecksum,
|
|
30112
|
+
exists: true
|
|
30113
|
+
};
|
|
30114
|
+
}
|
|
30115
|
+
static async checkBatch(filePaths, metadata, claudeDir) {
|
|
30116
|
+
const results = await Promise.all(filePaths.map((path9) => OwnershipChecker.checkOwnership(path9, metadata, claudeDir)));
|
|
30117
|
+
return new Map(results.map((r2) => [r2.path, r2]));
|
|
30118
|
+
}
|
|
30119
|
+
}
|
|
30120
|
+
|
|
30121
|
+
// src/domains/installation/selective-merger.ts
|
|
30122
|
+
init_logger();
|
|
30123
|
+
|
|
30124
|
+
class SelectiveMerger {
|
|
30125
|
+
manifest;
|
|
30126
|
+
manifestMap;
|
|
30127
|
+
constructor(manifest) {
|
|
30128
|
+
this.manifest = manifest;
|
|
30129
|
+
this.manifestMap = new Map;
|
|
30130
|
+
if (manifest) {
|
|
30131
|
+
for (const file of manifest.files) {
|
|
30132
|
+
this.manifestMap.set(file.path, file);
|
|
30133
|
+
}
|
|
30134
|
+
}
|
|
30135
|
+
}
|
|
30136
|
+
async shouldCopyFile(destPath, relativePath) {
|
|
30137
|
+
let destStat;
|
|
30138
|
+
try {
|
|
30139
|
+
destStat = await stat2(destPath);
|
|
30140
|
+
} catch {
|
|
30141
|
+
return { changed: true, reason: "new" };
|
|
30142
|
+
}
|
|
30143
|
+
const manifestEntry = this.manifestMap.get(relativePath);
|
|
30144
|
+
if (!manifestEntry) {
|
|
30145
|
+
logger.debug(`No manifest entry for ${relativePath}, will copy`);
|
|
30146
|
+
return { changed: true, reason: "new" };
|
|
30147
|
+
}
|
|
30148
|
+
if (destStat.size !== manifestEntry.size) {
|
|
30149
|
+
logger.debug(`Size differs for ${relativePath}: ${destStat.size} vs ${manifestEntry.size}`);
|
|
30150
|
+
return {
|
|
30151
|
+
changed: true,
|
|
30152
|
+
reason: "size-differ",
|
|
30153
|
+
sourceChecksum: manifestEntry.checksum
|
|
30154
|
+
};
|
|
30155
|
+
}
|
|
30156
|
+
const destChecksum = await OwnershipChecker.calculateChecksum(destPath);
|
|
30157
|
+
if (destChecksum !== manifestEntry.checksum) {
|
|
30158
|
+
logger.debug(`Checksum differs for ${relativePath}`);
|
|
30159
|
+
return {
|
|
30160
|
+
changed: true,
|
|
30161
|
+
reason: "checksum-differ",
|
|
30162
|
+
sourceChecksum: manifestEntry.checksum,
|
|
30163
|
+
destChecksum
|
|
30164
|
+
};
|
|
30165
|
+
}
|
|
30166
|
+
logger.debug(`Unchanged: ${relativePath}`);
|
|
30167
|
+
return {
|
|
30168
|
+
changed: false,
|
|
30169
|
+
reason: "unchanged",
|
|
30170
|
+
sourceChecksum: manifestEntry.checksum,
|
|
30171
|
+
destChecksum
|
|
30172
|
+
};
|
|
30173
|
+
}
|
|
30174
|
+
hasManifest() {
|
|
30175
|
+
return this.manifest !== null && this.manifestMap.size > 0;
|
|
30176
|
+
}
|
|
30177
|
+
getManifestFileCount() {
|
|
30178
|
+
return this.manifestMap.size;
|
|
30179
|
+
}
|
|
30180
|
+
}
|
|
30181
|
+
|
|
29167
30182
|
// src/domains/installation/file-merger.ts
|
|
29168
30183
|
class FileMerger {
|
|
29169
30184
|
neverCopyChecker = import_ignore2.default().add(NEVER_COPY_PATTERNS);
|
|
@@ -29173,6 +30188,8 @@ class FileMerger {
|
|
|
29173
30188
|
forceOverwriteSettings = false;
|
|
29174
30189
|
installedFiles = new Set;
|
|
29175
30190
|
installedDirectories = new Set;
|
|
30191
|
+
selectiveMerger = null;
|
|
30192
|
+
unchangedSkipped = 0;
|
|
29176
30193
|
setIncludePatterns(patterns) {
|
|
29177
30194
|
this.includePatterns = patterns;
|
|
29178
30195
|
}
|
|
@@ -29182,6 +30199,12 @@ class FileMerger {
|
|
|
29182
30199
|
setForceOverwriteSettings(force) {
|
|
29183
30200
|
this.forceOverwriteSettings = force;
|
|
29184
30201
|
}
|
|
30202
|
+
setManifest(manifest) {
|
|
30203
|
+
this.selectiveMerger = manifest ? new SelectiveMerger(manifest) : null;
|
|
30204
|
+
if (manifest && this.selectiveMerger?.hasManifest()) {
|
|
30205
|
+
logger.debug(`Selective merge enabled with ${this.selectiveMerger.getManifestFileCount()} tracked files`);
|
|
30206
|
+
}
|
|
30207
|
+
}
|
|
29185
30208
|
async merge(sourceDir, destDir, skipConfirmation = false) {
|
|
29186
30209
|
const conflicts = await this.detectConflicts(sourceDir, destDir);
|
|
29187
30210
|
if (conflicts.length > 0 && !skipConfirmation) {
|
|
@@ -29203,7 +30226,7 @@ class FileMerger {
|
|
|
29203
30226
|
const conflicts = [];
|
|
29204
30227
|
const files = await this.getFiles(sourceDir, sourceDir);
|
|
29205
30228
|
for (const file of files) {
|
|
29206
|
-
const relativePath =
|
|
30229
|
+
const relativePath = relative3(sourceDir, file);
|
|
29207
30230
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
29208
30231
|
const destPath = join12(destDir, relativePath);
|
|
29209
30232
|
if (await import_fs_extra3.pathExists(destPath)) {
|
|
@@ -29225,7 +30248,7 @@ class FileMerger {
|
|
|
29225
30248
|
let copiedCount = 0;
|
|
29226
30249
|
let skippedCount = 0;
|
|
29227
30250
|
for (const file of files) {
|
|
29228
|
-
const relativePath =
|
|
30251
|
+
const relativePath = relative3(sourceDir, file);
|
|
29229
30252
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
29230
30253
|
const destPath = join12(destDir, relativePath);
|
|
29231
30254
|
if (this.neverCopyChecker.ignores(normalizedRelativePath)) {
|
|
@@ -29248,11 +30271,24 @@ class FileMerger {
|
|
|
29248
30271
|
copiedCount++;
|
|
29249
30272
|
continue;
|
|
29250
30273
|
}
|
|
30274
|
+
if (this.selectiveMerger?.hasManifest()) {
|
|
30275
|
+
const compareResult = await this.selectiveMerger.shouldCopyFile(destPath, normalizedRelativePath);
|
|
30276
|
+
if (!compareResult.changed) {
|
|
30277
|
+
logger.debug(`Skipping unchanged: ${normalizedRelativePath}`);
|
|
30278
|
+
this.unchangedSkipped++;
|
|
30279
|
+
this.trackInstalledFile(normalizedRelativePath);
|
|
30280
|
+
continue;
|
|
30281
|
+
}
|
|
30282
|
+
}
|
|
29251
30283
|
await import_fs_extra3.copy(file, destPath, { overwrite: true });
|
|
29252
30284
|
this.trackInstalledFile(normalizedRelativePath);
|
|
29253
30285
|
copiedCount++;
|
|
29254
30286
|
}
|
|
29255
|
-
|
|
30287
|
+
if (this.unchangedSkipped > 0) {
|
|
30288
|
+
logger.success(`Updated ${copiedCount} file(s), skipped ${this.unchangedSkipped} unchanged, skipped ${skippedCount} protected`);
|
|
30289
|
+
} else {
|
|
30290
|
+
logger.success(`Copied ${copiedCount} file(s), skipped ${skippedCount} protected file(s)`);
|
|
30291
|
+
}
|
|
29256
30292
|
}
|
|
29257
30293
|
async processSettingsJson(sourceFile, destFile) {
|
|
29258
30294
|
try {
|
|
@@ -29343,7 +30379,7 @@ class FileMerger {
|
|
|
29343
30379
|
const entries = await import_fs_extra3.readdir(dir, { encoding: "utf8" });
|
|
29344
30380
|
for (const entry of entries) {
|
|
29345
30381
|
const fullPath = join12(dir, entry);
|
|
29346
|
-
const relativePath =
|
|
30382
|
+
const relativePath = relative3(baseDir, fullPath);
|
|
29347
30383
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
29348
30384
|
const stats = await import_fs_extra3.lstat(fullPath);
|
|
29349
30385
|
if (stats.isSymbolicLink()) {
|
|
@@ -29602,14 +30638,165 @@ async function runSetupWizard(options) {
|
|
|
29602
30638
|
}
|
|
29603
30639
|
|
|
29604
30640
|
// src/domains/migration/legacy-migration.ts
|
|
29605
|
-
import { readdir as readdir4, stat as
|
|
29606
|
-
import { join as
|
|
30641
|
+
import { readdir as readdir4, stat as stat3 } from "node:fs/promises";
|
|
30642
|
+
import { join as join19, relative as relative4 } from "node:path";
|
|
29607
30643
|
|
|
29608
30644
|
// src/services/file-operations/manifest-writer.ts
|
|
30645
|
+
import { join as join17 } from "node:path";
|
|
30646
|
+
|
|
30647
|
+
// src/domains/migration/metadata-migration.ts
|
|
29609
30648
|
init_logger();
|
|
29610
|
-
init_types2();
|
|
29611
30649
|
var import_fs_extra7 = __toESM(require_lib(), 1);
|
|
29612
30650
|
import { join as join16 } from "node:path";
|
|
30651
|
+
async function detectMetadataFormat(claudeDir) {
|
|
30652
|
+
const metadataPath = join16(claudeDir, "metadata.json");
|
|
30653
|
+
if (!await import_fs_extra7.pathExists(metadataPath)) {
|
|
30654
|
+
return { format: "none", metadata: null, detectedKit: null };
|
|
30655
|
+
}
|
|
30656
|
+
try {
|
|
30657
|
+
const content = await import_fs_extra7.readFile(metadataPath, "utf-8");
|
|
30658
|
+
const parsed = JSON.parse(content);
|
|
30659
|
+
if (parsed.kits && Object.keys(parsed.kits).length > 0) {
|
|
30660
|
+
const installedKits = Object.keys(parsed.kits);
|
|
30661
|
+
return {
|
|
30662
|
+
format: "multi-kit",
|
|
30663
|
+
metadata: parsed,
|
|
30664
|
+
detectedKit: installedKits[0] || null
|
|
30665
|
+
};
|
|
30666
|
+
}
|
|
30667
|
+
if (parsed.name || parsed.version || parsed.files) {
|
|
30668
|
+
let detectedKit = null;
|
|
30669
|
+
const nameToCheck = parsed.name || "";
|
|
30670
|
+
if (/\bengineer\b/i.test(nameToCheck)) {
|
|
30671
|
+
detectedKit = "engineer";
|
|
30672
|
+
} else if (/\bmarketing\b/i.test(nameToCheck)) {
|
|
30673
|
+
detectedKit = "marketing";
|
|
30674
|
+
} else {
|
|
30675
|
+
detectedKit = "engineer";
|
|
30676
|
+
}
|
|
30677
|
+
return { format: "legacy", metadata: parsed, detectedKit };
|
|
30678
|
+
}
|
|
30679
|
+
logger.warning("Metadata file exists but has unrecognized format (missing kits, name, version, or files)");
|
|
30680
|
+
return { format: "none", metadata: null, detectedKit: null };
|
|
30681
|
+
} catch (error) {
|
|
30682
|
+
logger.warning(`Failed to read metadata file (may be corrupted): ${error}`);
|
|
30683
|
+
return { format: "none", metadata: null, detectedKit: null };
|
|
30684
|
+
}
|
|
30685
|
+
}
|
|
30686
|
+
async function migrateToMultiKit(claudeDir) {
|
|
30687
|
+
const detection = await detectMetadataFormat(claudeDir);
|
|
30688
|
+
if (detection.format === "multi-kit") {
|
|
30689
|
+
return {
|
|
30690
|
+
success: true,
|
|
30691
|
+
migrated: false,
|
|
30692
|
+
fromFormat: "multi-kit",
|
|
30693
|
+
toFormat: "multi-kit"
|
|
30694
|
+
};
|
|
30695
|
+
}
|
|
30696
|
+
if (detection.format === "none") {
|
|
30697
|
+
return {
|
|
30698
|
+
success: true,
|
|
30699
|
+
migrated: false,
|
|
30700
|
+
fromFormat: "none",
|
|
30701
|
+
toFormat: "multi-kit"
|
|
30702
|
+
};
|
|
30703
|
+
}
|
|
30704
|
+
const metadataPath = join16(claudeDir, "metadata.json");
|
|
30705
|
+
const legacy = detection.metadata;
|
|
30706
|
+
if (!legacy) {
|
|
30707
|
+
return {
|
|
30708
|
+
success: false,
|
|
30709
|
+
migrated: false,
|
|
30710
|
+
fromFormat: "legacy",
|
|
30711
|
+
toFormat: "multi-kit",
|
|
30712
|
+
error: "Metadata exists but could not be read"
|
|
30713
|
+
};
|
|
30714
|
+
}
|
|
30715
|
+
const legacyKit = detection.detectedKit || "engineer";
|
|
30716
|
+
try {
|
|
30717
|
+
const kitMetadata = {
|
|
30718
|
+
version: legacy.version || "unknown",
|
|
30719
|
+
installedAt: legacy.installedAt || new Date().toISOString(),
|
|
30720
|
+
files: legacy.files || []
|
|
30721
|
+
};
|
|
30722
|
+
const multiKit = {
|
|
30723
|
+
kits: {
|
|
30724
|
+
[legacyKit]: kitMetadata
|
|
30725
|
+
},
|
|
30726
|
+
scope: legacy.scope,
|
|
30727
|
+
name: legacy.name,
|
|
30728
|
+
version: legacy.version,
|
|
30729
|
+
installedAt: legacy.installedAt,
|
|
30730
|
+
installedFiles: legacy.installedFiles,
|
|
30731
|
+
userConfigFiles: legacy.userConfigFiles,
|
|
30732
|
+
files: legacy.files
|
|
30733
|
+
};
|
|
30734
|
+
await import_fs_extra7.writeFile(metadataPath, JSON.stringify(multiKit, null, 2), "utf-8");
|
|
30735
|
+
logger.info(`Migrated metadata from legacy format to multi-kit (detected: ${legacyKit})`);
|
|
30736
|
+
return {
|
|
30737
|
+
success: true,
|
|
30738
|
+
migrated: true,
|
|
30739
|
+
fromFormat: "legacy",
|
|
30740
|
+
toFormat: "multi-kit"
|
|
30741
|
+
};
|
|
30742
|
+
} catch (error) {
|
|
30743
|
+
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
30744
|
+
logger.error(`Metadata migration failed: ${errorMsg}`);
|
|
30745
|
+
return {
|
|
30746
|
+
success: false,
|
|
30747
|
+
migrated: false,
|
|
30748
|
+
fromFormat: "legacy",
|
|
30749
|
+
toFormat: "multi-kit",
|
|
30750
|
+
error: errorMsg
|
|
30751
|
+
};
|
|
30752
|
+
}
|
|
30753
|
+
}
|
|
30754
|
+
function getKitMetadata(metadata, kit) {
|
|
30755
|
+
if (metadata.kits?.[kit]) {
|
|
30756
|
+
return metadata.kits[kit];
|
|
30757
|
+
}
|
|
30758
|
+
if (!metadata.kits && metadata.version) {
|
|
30759
|
+
return {
|
|
30760
|
+
version: metadata.version,
|
|
30761
|
+
installedAt: metadata.installedAt || "",
|
|
30762
|
+
files: metadata.files
|
|
30763
|
+
};
|
|
30764
|
+
}
|
|
30765
|
+
return null;
|
|
30766
|
+
}
|
|
30767
|
+
function getAllTrackedFiles(metadata) {
|
|
30768
|
+
if (metadata.kits) {
|
|
30769
|
+
const allFiles = [];
|
|
30770
|
+
for (const kit of Object.values(metadata.kits)) {
|
|
30771
|
+
if (kit.files) {
|
|
30772
|
+
allFiles.push(...kit.files);
|
|
30773
|
+
}
|
|
30774
|
+
}
|
|
30775
|
+
return allFiles;
|
|
30776
|
+
}
|
|
30777
|
+
return metadata.files || [];
|
|
30778
|
+
}
|
|
30779
|
+
function getInstalledKits(metadata) {
|
|
30780
|
+
if (metadata.kits) {
|
|
30781
|
+
return Object.keys(metadata.kits);
|
|
30782
|
+
}
|
|
30783
|
+
const nameToCheck = metadata.name || "";
|
|
30784
|
+
if (/\bengineer\b/i.test(nameToCheck)) {
|
|
30785
|
+
return ["engineer"];
|
|
30786
|
+
}
|
|
30787
|
+
if (/\bmarketing\b/i.test(nameToCheck)) {
|
|
30788
|
+
return ["marketing"];
|
|
30789
|
+
}
|
|
30790
|
+
if (metadata.version) {
|
|
30791
|
+
return ["engineer"];
|
|
30792
|
+
}
|
|
30793
|
+
return [];
|
|
30794
|
+
}
|
|
30795
|
+
|
|
30796
|
+
// src/services/file-operations/manifest-writer.ts
|
|
30797
|
+
init_logger();
|
|
30798
|
+
init_types2();
|
|
30799
|
+
var import_fs_extra8 = __toESM(require_lib(), 1);
|
|
29613
30800
|
|
|
29614
30801
|
// node_modules/yocto-queue/index.js
|
|
29615
30802
|
class Node2 {
|
|
@@ -29751,66 +30938,8 @@ function validateConcurrency(concurrency) {
|
|
|
29751
30938
|
}
|
|
29752
30939
|
}
|
|
29753
30940
|
|
|
29754
|
-
// src/services/file-operations/ownership-checker.ts
|
|
29755
|
-
import { createHash } from "node:crypto";
|
|
29756
|
-
import { createReadStream } from "node:fs";
|
|
29757
|
-
import { stat } from "node:fs/promises";
|
|
29758
|
-
import { relative as relative3 } from "node:path";
|
|
29759
|
-
|
|
29760
|
-
class OwnershipChecker {
|
|
29761
|
-
static async calculateChecksum(filePath) {
|
|
29762
|
-
return new Promise((resolve3, reject) => {
|
|
29763
|
-
const hash = createHash("sha256");
|
|
29764
|
-
const stream = createReadStream(filePath);
|
|
29765
|
-
stream.on("data", (chunk) => hash.update(chunk));
|
|
29766
|
-
stream.on("end", () => {
|
|
29767
|
-
resolve3(hash.digest("hex"));
|
|
29768
|
-
});
|
|
29769
|
-
stream.on("error", (err) => {
|
|
29770
|
-
stream.destroy();
|
|
29771
|
-
reject(new Error(`Failed to calculate checksum for "${filePath}": ${err.message}`));
|
|
29772
|
-
});
|
|
29773
|
-
});
|
|
29774
|
-
}
|
|
29775
|
-
static async checkOwnership(filePath, metadata, claudeDir) {
|
|
29776
|
-
try {
|
|
29777
|
-
await stat(filePath);
|
|
29778
|
-
} catch {
|
|
29779
|
-
return { path: filePath, ownership: "user", exists: false };
|
|
29780
|
-
}
|
|
29781
|
-
if (!metadata || !metadata.files || metadata.files.length === 0) {
|
|
29782
|
-
return { path: filePath, ownership: "user", exists: true };
|
|
29783
|
-
}
|
|
29784
|
-
const relativePath = relative3(claudeDir, filePath).replace(/\\/g, "/");
|
|
29785
|
-
const tracked = metadata.files.find((f3) => f3.path === relativePath);
|
|
29786
|
-
if (!tracked) {
|
|
29787
|
-
return { path: filePath, ownership: "user", exists: true };
|
|
29788
|
-
}
|
|
29789
|
-
const actualChecksum = await OwnershipChecker.calculateChecksum(filePath);
|
|
29790
|
-
if (actualChecksum === tracked.checksum) {
|
|
29791
|
-
return {
|
|
29792
|
-
path: filePath,
|
|
29793
|
-
ownership: "ck",
|
|
29794
|
-
expectedChecksum: tracked.checksum,
|
|
29795
|
-
actualChecksum,
|
|
29796
|
-
exists: true
|
|
29797
|
-
};
|
|
29798
|
-
}
|
|
29799
|
-
return {
|
|
29800
|
-
path: filePath,
|
|
29801
|
-
ownership: "ck-modified",
|
|
29802
|
-
expectedChecksum: tracked.checksum,
|
|
29803
|
-
actualChecksum,
|
|
29804
|
-
exists: true
|
|
29805
|
-
};
|
|
29806
|
-
}
|
|
29807
|
-
static async checkBatch(filePaths, metadata, claudeDir) {
|
|
29808
|
-
const results = await Promise.all(filePaths.map((path9) => OwnershipChecker.checkOwnership(path9, metadata, claudeDir)));
|
|
29809
|
-
return new Map(results.map((r2) => [r2.path, r2]));
|
|
29810
|
-
}
|
|
29811
|
-
}
|
|
29812
|
-
|
|
29813
30941
|
// src/services/file-operations/manifest-writer.ts
|
|
30942
|
+
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
29814
30943
|
class ManifestWriter {
|
|
29815
30944
|
installedFiles = new Set;
|
|
29816
30945
|
userConfigFiles = new Set;
|
|
@@ -29866,13 +30995,16 @@ class ManifestWriter {
|
|
|
29866
30995
|
return false;
|
|
29867
30996
|
}
|
|
29868
30997
|
}));
|
|
29869
|
-
let completed = 0;
|
|
29870
30998
|
const progressInterval = Math.max(1, Math.floor(total / 20));
|
|
29871
|
-
|
|
30999
|
+
let reportedProgress = 0;
|
|
31000
|
+
const results = await Promise.all(tasks.map(async (task, index) => {
|
|
29872
31001
|
const result = await task;
|
|
29873
|
-
completed
|
|
31002
|
+
const completed = index + 1;
|
|
29874
31003
|
if (completed % progressInterval === 0 || completed === total) {
|
|
29875
|
-
|
|
31004
|
+
if (completed > reportedProgress) {
|
|
31005
|
+
reportedProgress = completed;
|
|
31006
|
+
onProgress?.(completed, total);
|
|
31007
|
+
}
|
|
29876
31008
|
}
|
|
29877
31009
|
return result;
|
|
29878
31010
|
}));
|
|
@@ -29886,39 +31018,70 @@ class ManifestWriter {
|
|
|
29886
31018
|
getTrackedFiles() {
|
|
29887
31019
|
return Array.from(this.trackedFiles.values()).sort((a3, b3) => a3.path.localeCompare(b3.path));
|
|
29888
31020
|
}
|
|
29889
|
-
async writeManifest(claudeDir, kitName, version, scope) {
|
|
29890
|
-
const metadataPath =
|
|
29891
|
-
|
|
29892
|
-
|
|
29893
|
-
|
|
29894
|
-
|
|
29895
|
-
|
|
29896
|
-
|
|
29897
|
-
|
|
31021
|
+
async writeManifest(claudeDir, kitName, version, scope, kitType) {
|
|
31022
|
+
const metadataPath = join17(claudeDir, "metadata.json");
|
|
31023
|
+
const kit = kitType || (/\bmarketing\b/i.test(kitName) ? "marketing" : "engineer");
|
|
31024
|
+
await import_fs_extra8.ensureFile(metadataPath);
|
|
31025
|
+
let release = null;
|
|
31026
|
+
try {
|
|
31027
|
+
release = await import_proper_lockfile.lock(metadataPath, {
|
|
31028
|
+
retries: { retries: 5, minTimeout: 100, maxTimeout: 1000 },
|
|
31029
|
+
stale: 60000
|
|
31030
|
+
});
|
|
31031
|
+
logger.debug(`Acquired lock on ${metadataPath}`);
|
|
31032
|
+
const migrationResult = await migrateToMultiKit(claudeDir);
|
|
31033
|
+
if (!migrationResult.success) {
|
|
31034
|
+
logger.warning(`Metadata migration warning: ${migrationResult.error}`);
|
|
31035
|
+
}
|
|
31036
|
+
let existingMetadata = { kits: {} };
|
|
31037
|
+
if (await import_fs_extra8.pathExists(metadataPath)) {
|
|
31038
|
+
try {
|
|
31039
|
+
const content = await import_fs_extra8.readFile(metadataPath, "utf-8");
|
|
31040
|
+
const parsed = JSON.parse(content);
|
|
31041
|
+
if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
|
|
31042
|
+
existingMetadata = parsed;
|
|
31043
|
+
}
|
|
31044
|
+
} catch (error) {
|
|
31045
|
+
logger.debug(`Could not read existing metadata: ${error}`);
|
|
31046
|
+
}
|
|
31047
|
+
}
|
|
31048
|
+
const trackedFiles = this.getTrackedFiles();
|
|
31049
|
+
const installedAt = new Date().toISOString();
|
|
31050
|
+
const kitMetadata = {
|
|
31051
|
+
version,
|
|
31052
|
+
installedAt,
|
|
31053
|
+
files: trackedFiles.length > 0 ? trackedFiles : undefined
|
|
31054
|
+
};
|
|
31055
|
+
const metadata = {
|
|
31056
|
+
kits: {
|
|
31057
|
+
...existingMetadata.kits,
|
|
31058
|
+
[kit]: kitMetadata
|
|
31059
|
+
},
|
|
31060
|
+
scope,
|
|
31061
|
+
name: kitName,
|
|
31062
|
+
version,
|
|
31063
|
+
installedAt,
|
|
31064
|
+
installedFiles: this.getInstalledFiles(),
|
|
31065
|
+
userConfigFiles: [...USER_CONFIG_PATTERNS, ...this.getUserConfigFiles()],
|
|
31066
|
+
files: trackedFiles.length > 0 ? trackedFiles : undefined
|
|
31067
|
+
};
|
|
31068
|
+
const validated = MetadataSchema.parse(metadata);
|
|
31069
|
+
await import_fs_extra8.writeFile(metadataPath, JSON.stringify(validated, null, 2), "utf-8");
|
|
31070
|
+
logger.debug(`Wrote manifest for kit "${kit}" with ${trackedFiles.length} tracked files`);
|
|
31071
|
+
} finally {
|
|
31072
|
+
if (release) {
|
|
31073
|
+
await release();
|
|
31074
|
+
logger.debug(`Released lock on ${metadataPath}`);
|
|
29898
31075
|
}
|
|
29899
31076
|
}
|
|
29900
|
-
const trackedFiles = this.getTrackedFiles();
|
|
29901
|
-
const metadata = {
|
|
29902
|
-
...existingMetadata,
|
|
29903
|
-
name: kitName,
|
|
29904
|
-
version,
|
|
29905
|
-
installedAt: new Date().toISOString(),
|
|
29906
|
-
scope,
|
|
29907
|
-
installedFiles: this.getInstalledFiles(),
|
|
29908
|
-
userConfigFiles: [...USER_CONFIG_PATTERNS, ...this.getUserConfigFiles()],
|
|
29909
|
-
files: trackedFiles.length > 0 ? trackedFiles : undefined
|
|
29910
|
-
};
|
|
29911
|
-
const validated = MetadataSchema.parse(metadata);
|
|
29912
|
-
await import_fs_extra7.writeFile(metadataPath, JSON.stringify(validated, null, 2), "utf-8");
|
|
29913
|
-
logger.debug(`Wrote manifest with ${this.installedFiles.size} installed files, ${trackedFiles.length} tracked`);
|
|
29914
31077
|
}
|
|
29915
31078
|
static async readManifest(claudeDir) {
|
|
29916
|
-
const metadataPath =
|
|
29917
|
-
if (!await
|
|
31079
|
+
const metadataPath = join17(claudeDir, "metadata.json");
|
|
31080
|
+
if (!await import_fs_extra8.pathExists(metadataPath)) {
|
|
29918
31081
|
return null;
|
|
29919
31082
|
}
|
|
29920
31083
|
try {
|
|
29921
|
-
const content = await
|
|
31084
|
+
const content = await import_fs_extra8.readFile(metadataPath, "utf-8");
|
|
29922
31085
|
const parsed = JSON.parse(content);
|
|
29923
31086
|
return MetadataSchema.parse(parsed);
|
|
29924
31087
|
} catch (error) {
|
|
@@ -29926,13 +31089,82 @@ class ManifestWriter {
|
|
|
29926
31089
|
return null;
|
|
29927
31090
|
}
|
|
29928
31091
|
}
|
|
29929
|
-
static async
|
|
31092
|
+
static async readKitManifest(claudeDir, kit) {
|
|
29930
31093
|
const metadata = await ManifestWriter.readManifest(claudeDir);
|
|
29931
|
-
if (metadata
|
|
31094
|
+
if (!metadata)
|
|
31095
|
+
return null;
|
|
31096
|
+
return getKitMetadata(metadata, kit);
|
|
31097
|
+
}
|
|
31098
|
+
static async getUninstallManifest(claudeDir, kit) {
|
|
31099
|
+
const detection = await detectMetadataFormat(claudeDir);
|
|
31100
|
+
if (detection.format === "multi-kit" && detection.metadata?.kits) {
|
|
31101
|
+
const installedKits = Object.keys(detection.metadata.kits);
|
|
31102
|
+
if (kit) {
|
|
31103
|
+
const kitMeta = detection.metadata.kits[kit];
|
|
31104
|
+
if (!kitMeta?.files) {
|
|
31105
|
+
return {
|
|
31106
|
+
filesToRemove: [],
|
|
31107
|
+
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
31108
|
+
hasManifest: true,
|
|
31109
|
+
isMultiKit: true,
|
|
31110
|
+
remainingKits: installedKits.filter((k2) => k2 !== kit)
|
|
31111
|
+
};
|
|
31112
|
+
}
|
|
31113
|
+
const kitFiles = kitMeta.files.map((f3) => f3.path);
|
|
31114
|
+
const sharedFiles = new Set;
|
|
31115
|
+
for (const otherKit of installedKits) {
|
|
31116
|
+
if (otherKit !== kit) {
|
|
31117
|
+
const otherMeta = detection.metadata.kits[otherKit];
|
|
31118
|
+
if (otherMeta?.files) {
|
|
31119
|
+
for (const f3 of otherMeta.files) {
|
|
31120
|
+
sharedFiles.add(f3.path);
|
|
31121
|
+
}
|
|
31122
|
+
}
|
|
31123
|
+
}
|
|
31124
|
+
}
|
|
31125
|
+
const filesToRemove = kitFiles.filter((f3) => !sharedFiles.has(f3));
|
|
31126
|
+
const filesToPreserve = [
|
|
31127
|
+
...USER_CONFIG_PATTERNS,
|
|
31128
|
+
...kitFiles.filter((f3) => sharedFiles.has(f3))
|
|
31129
|
+
];
|
|
31130
|
+
return {
|
|
31131
|
+
filesToRemove,
|
|
31132
|
+
filesToPreserve,
|
|
31133
|
+
hasManifest: true,
|
|
31134
|
+
isMultiKit: true,
|
|
31135
|
+
remainingKits: installedKits.filter((k2) => k2 !== kit)
|
|
31136
|
+
};
|
|
31137
|
+
}
|
|
31138
|
+
const allFiles = getAllTrackedFiles(detection.metadata);
|
|
29932
31139
|
return {
|
|
29933
|
-
filesToRemove:
|
|
29934
|
-
filesToPreserve:
|
|
29935
|
-
hasManifest: true
|
|
31140
|
+
filesToRemove: allFiles.map((f3) => f3.path),
|
|
31141
|
+
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
31142
|
+
hasManifest: true,
|
|
31143
|
+
isMultiKit: true,
|
|
31144
|
+
remainingKits: []
|
|
31145
|
+
};
|
|
31146
|
+
}
|
|
31147
|
+
if (detection.format === "legacy" && detection.metadata) {
|
|
31148
|
+
const legacyFiles2 = detection.metadata.files?.map((f3) => f3.path) || [];
|
|
31149
|
+
const installedFiles = detection.metadata.installedFiles || [];
|
|
31150
|
+
const hasFiles = legacyFiles2.length > 0 || installedFiles.length > 0;
|
|
31151
|
+
if (!hasFiles) {
|
|
31152
|
+
const legacyDirs2 = ["commands", "agents", "skills", "workflows", "hooks", "scripts"];
|
|
31153
|
+
const legacyFileList = ["metadata.json"];
|
|
31154
|
+
return {
|
|
31155
|
+
filesToRemove: [...legacyDirs2, ...legacyFileList],
|
|
31156
|
+
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
31157
|
+
hasManifest: false,
|
|
31158
|
+
isMultiKit: false,
|
|
31159
|
+
remainingKits: []
|
|
31160
|
+
};
|
|
31161
|
+
}
|
|
31162
|
+
return {
|
|
31163
|
+
filesToRemove: legacyFiles2.length > 0 ? legacyFiles2 : installedFiles,
|
|
31164
|
+
filesToPreserve: detection.metadata.userConfigFiles || USER_CONFIG_PATTERNS,
|
|
31165
|
+
hasManifest: true,
|
|
31166
|
+
isMultiKit: false,
|
|
31167
|
+
remainingKits: []
|
|
29936
31168
|
};
|
|
29937
31169
|
}
|
|
29938
31170
|
const legacyDirs = ["commands", "agents", "skills", "workflows", "hooks", "scripts"];
|
|
@@ -29940,20 +31172,55 @@ class ManifestWriter {
|
|
|
29940
31172
|
return {
|
|
29941
31173
|
filesToRemove: [...legacyDirs, ...legacyFiles],
|
|
29942
31174
|
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
29943
|
-
hasManifest: false
|
|
31175
|
+
hasManifest: false,
|
|
31176
|
+
isMultiKit: false,
|
|
31177
|
+
remainingKits: []
|
|
29944
31178
|
};
|
|
29945
31179
|
}
|
|
31180
|
+
static async removeKitFromManifest(claudeDir, kit) {
|
|
31181
|
+
const metadataPath = join17(claudeDir, "metadata.json");
|
|
31182
|
+
if (!await import_fs_extra8.pathExists(metadataPath))
|
|
31183
|
+
return false;
|
|
31184
|
+
let release = null;
|
|
31185
|
+
try {
|
|
31186
|
+
release = await import_proper_lockfile.lock(metadataPath, {
|
|
31187
|
+
retries: { retries: 5, minTimeout: 100, maxTimeout: 1000 },
|
|
31188
|
+
stale: 60000
|
|
31189
|
+
});
|
|
31190
|
+
logger.debug(`Acquired lock on ${metadataPath} for kit removal`);
|
|
31191
|
+
const metadata = await ManifestWriter.readManifest(claudeDir);
|
|
31192
|
+
if (!metadata?.kits?.[kit])
|
|
31193
|
+
return false;
|
|
31194
|
+
const { [kit]: _removed, ...remainingKits } = metadata.kits;
|
|
31195
|
+
if (Object.keys(remainingKits).length === 0) {
|
|
31196
|
+
logger.debug("No kits remaining, metadata.json will be cleaned up");
|
|
31197
|
+
return true;
|
|
31198
|
+
}
|
|
31199
|
+
const updated = {
|
|
31200
|
+
...metadata,
|
|
31201
|
+
kits: remainingKits
|
|
31202
|
+
};
|
|
31203
|
+
await import_fs_extra8.writeFile(metadataPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
31204
|
+
logger.debug(`Removed kit "${kit}" from metadata, ${Object.keys(remainingKits).length} kit(s) remaining`);
|
|
31205
|
+
return true;
|
|
31206
|
+
} finally {
|
|
31207
|
+
if (release) {
|
|
31208
|
+
await release();
|
|
31209
|
+
logger.debug(`Released lock on ${metadataPath}`);
|
|
31210
|
+
}
|
|
31211
|
+
}
|
|
31212
|
+
}
|
|
29946
31213
|
}
|
|
29947
31214
|
|
|
29948
31215
|
// src/domains/migration/legacy-migration.ts
|
|
29949
31216
|
init_logger();
|
|
29950
|
-
var
|
|
31217
|
+
var import_fs_extra10 = __toESM(require_lib(), 1);
|
|
29951
31218
|
|
|
29952
31219
|
// src/domains/migration/release-manifest.ts
|
|
29953
31220
|
init_logger();
|
|
29954
31221
|
init_zod();
|
|
29955
|
-
var
|
|
29956
|
-
import { join as
|
|
31222
|
+
var import_fs_extra9 = __toESM(require_lib(), 1);
|
|
31223
|
+
import { join as join18 } from "node:path";
|
|
29957
31224
|
var ReleaseManifestFileSchema = exports_external.object({
|
|
29958
31225
|
path: exports_external.string(),
|
|
29959
31226
|
checksum: exports_external.string().regex(/^[a-f0-9]{64}$/),
|
|
@@ -29967,9 +31234,9 @@ var ReleaseManifestSchema = exports_external.object({
|
|
|
29967
31234
|
|
|
29968
31235
|
class ReleaseManifestLoader {
|
|
29969
31236
|
static async load(extractDir) {
|
|
29970
|
-
const manifestPath =
|
|
31237
|
+
const manifestPath = join18(extractDir, "release-manifest.json");
|
|
29971
31238
|
try {
|
|
29972
|
-
const content = await
|
|
31239
|
+
const content = await import_fs_extra9.readFile(manifestPath, "utf-8");
|
|
29973
31240
|
const parsed = JSON.parse(content);
|
|
29974
31241
|
return ReleaseManifestSchema.parse(parsed);
|
|
29975
31242
|
} catch (error) {
|
|
@@ -30013,10 +31280,10 @@ class LegacyMigration {
|
|
|
30013
31280
|
for (const entry of entries) {
|
|
30014
31281
|
if (entry === "metadata.json")
|
|
30015
31282
|
continue;
|
|
30016
|
-
const fullPath =
|
|
31283
|
+
const fullPath = join19(dir, entry);
|
|
30017
31284
|
let stats;
|
|
30018
31285
|
try {
|
|
30019
|
-
stats = await
|
|
31286
|
+
stats = await stat3(fullPath);
|
|
30020
31287
|
} catch (err) {
|
|
30021
31288
|
const error = err;
|
|
30022
31289
|
if (error.code === "ENOENT") {
|
|
@@ -30115,7 +31382,7 @@ User-created files (sample):`);
|
|
|
30115
31382
|
];
|
|
30116
31383
|
if (filesToChecksum.length > 0) {
|
|
30117
31384
|
const checksumResults = await Promise.all(filesToChecksum.map(async ({ relativePath, ownership }) => {
|
|
30118
|
-
const fullPath =
|
|
31385
|
+
const fullPath = join19(claudeDir, relativePath);
|
|
30119
31386
|
const checksum = await OwnershipChecker.calculateChecksum(fullPath);
|
|
30120
31387
|
return { relativePath, checksum, ownership };
|
|
30121
31388
|
}));
|
|
@@ -30136,8 +31403,8 @@ User-created files (sample):`);
|
|
|
30136
31403
|
installedAt: new Date().toISOString(),
|
|
30137
31404
|
files: trackedFiles
|
|
30138
31405
|
};
|
|
30139
|
-
const metadataPath =
|
|
30140
|
-
await
|
|
31406
|
+
const metadataPath = join19(claudeDir, "metadata.json");
|
|
31407
|
+
await import_fs_extra10.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
|
|
30141
31408
|
logger.success(`Migration complete: tracked ${trackedFiles.length} files`);
|
|
30142
31409
|
return true;
|
|
30143
31410
|
}
|
|
@@ -30145,24 +31412,24 @@ User-created files (sample):`);
|
|
|
30145
31412
|
|
|
30146
31413
|
// src/domains/skills/skills-detector.ts
|
|
30147
31414
|
init_logger();
|
|
30148
|
-
var
|
|
31415
|
+
var import_fs_extra12 = __toESM(require_lib(), 1);
|
|
30149
31416
|
import { readdir as readdir6 } from "node:fs/promises";
|
|
30150
|
-
import { join as
|
|
31417
|
+
import { join as join21 } from "node:path";
|
|
30151
31418
|
|
|
30152
31419
|
// src/domains/skills/skills-manifest.ts
|
|
30153
31420
|
init_logger();
|
|
30154
31421
|
init_types2();
|
|
30155
|
-
var
|
|
31422
|
+
var import_fs_extra11 = __toESM(require_lib(), 1);
|
|
30156
31423
|
import { createHash as createHash2 } from "node:crypto";
|
|
30157
|
-
import { readFile as
|
|
30158
|
-
import { join as
|
|
31424
|
+
import { readFile as readFile13, readdir as readdir5, writeFile as writeFile12 } from "node:fs/promises";
|
|
31425
|
+
import { join as join20, relative as relative5 } from "node:path";
|
|
30159
31426
|
|
|
30160
31427
|
class SkillsManifestManager {
|
|
30161
31428
|
static MANIFEST_FILENAME = ".skills-manifest.json";
|
|
30162
31429
|
static MANIFEST_VERSION = "1.0.0";
|
|
30163
31430
|
static async generateManifest(skillsDir) {
|
|
30164
31431
|
logger.debug(`Generating manifest for: ${skillsDir}`);
|
|
30165
|
-
if (!await
|
|
31432
|
+
if (!await import_fs_extra11.pathExists(skillsDir)) {
|
|
30166
31433
|
throw new SkillsMigrationError(`Skills directory does not exist: ${skillsDir}`);
|
|
30167
31434
|
}
|
|
30168
31435
|
const structure = await SkillsManifestManager.detectStructure(skillsDir);
|
|
@@ -30177,18 +31444,18 @@ class SkillsManifestManager {
|
|
|
30177
31444
|
return manifest;
|
|
30178
31445
|
}
|
|
30179
31446
|
static async writeManifest(skillsDir, manifest) {
|
|
30180
|
-
const manifestPath =
|
|
30181
|
-
await
|
|
31447
|
+
const manifestPath = join20(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
|
|
31448
|
+
await writeFile12(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
30182
31449
|
logger.debug(`Wrote manifest to: ${manifestPath}`);
|
|
30183
31450
|
}
|
|
30184
31451
|
static async readManifest(skillsDir) {
|
|
30185
|
-
const manifestPath =
|
|
30186
|
-
if (!await
|
|
31452
|
+
const manifestPath = join20(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
|
|
31453
|
+
if (!await import_fs_extra11.pathExists(manifestPath)) {
|
|
30187
31454
|
logger.debug(`No manifest found at: ${manifestPath}`);
|
|
30188
31455
|
return null;
|
|
30189
31456
|
}
|
|
30190
31457
|
try {
|
|
30191
|
-
const content = await
|
|
31458
|
+
const content = await readFile13(manifestPath, "utf-8");
|
|
30192
31459
|
const data = JSON.parse(content);
|
|
30193
31460
|
const manifest = SkillsManifestSchema.parse(data);
|
|
30194
31461
|
logger.debug(`Read manifest from: ${manifestPath}`);
|
|
@@ -30205,7 +31472,7 @@ class SkillsManifestManager {
|
|
|
30205
31472
|
return "flat";
|
|
30206
31473
|
}
|
|
30207
31474
|
for (const dir of dirs.slice(0, 3)) {
|
|
30208
|
-
const dirPath =
|
|
31475
|
+
const dirPath = join20(skillsDir, dir.name);
|
|
30209
31476
|
const subEntries = await readdir5(dirPath, { withFileTypes: true });
|
|
30210
31477
|
const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
|
|
30211
31478
|
if (hasSubdirs) {
|
|
@@ -30224,7 +31491,7 @@ class SkillsManifestManager {
|
|
|
30224
31491
|
const entries = await readdir5(skillsDir, { withFileTypes: true });
|
|
30225
31492
|
for (const entry of entries) {
|
|
30226
31493
|
if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith(".")) {
|
|
30227
|
-
const skillPath =
|
|
31494
|
+
const skillPath = join20(skillsDir, entry.name);
|
|
30228
31495
|
const hash = await SkillsManifestManager.hashDirectory(skillPath);
|
|
30229
31496
|
skills.push({
|
|
30230
31497
|
name: entry.name,
|
|
@@ -30236,11 +31503,11 @@ class SkillsManifestManager {
|
|
|
30236
31503
|
const categories = await readdir5(skillsDir, { withFileTypes: true });
|
|
30237
31504
|
for (const category of categories) {
|
|
30238
31505
|
if (category.isDirectory() && category.name !== "node_modules" && !category.name.startsWith(".")) {
|
|
30239
|
-
const categoryPath =
|
|
31506
|
+
const categoryPath = join20(skillsDir, category.name);
|
|
30240
31507
|
const skillEntries = await readdir5(categoryPath, { withFileTypes: true });
|
|
30241
31508
|
for (const skillEntry of skillEntries) {
|
|
30242
31509
|
if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
|
|
30243
|
-
const skillPath =
|
|
31510
|
+
const skillPath = join20(categoryPath, skillEntry.name);
|
|
30244
31511
|
const hash = await SkillsManifestManager.hashDirectory(skillPath);
|
|
30245
31512
|
skills.push({
|
|
30246
31513
|
name: skillEntry.name,
|
|
@@ -30260,7 +31527,7 @@ class SkillsManifestManager {
|
|
|
30260
31527
|
files.sort();
|
|
30261
31528
|
for (const file of files) {
|
|
30262
31529
|
const relativePath = relative5(dirPath, file);
|
|
30263
|
-
const content = await
|
|
31530
|
+
const content = await readFile13(file);
|
|
30264
31531
|
hash.update(relativePath);
|
|
30265
31532
|
hash.update(content);
|
|
30266
31533
|
}
|
|
@@ -30270,7 +31537,7 @@ class SkillsManifestManager {
|
|
|
30270
31537
|
const files = [];
|
|
30271
31538
|
const entries = await readdir5(dirPath, { withFileTypes: true });
|
|
30272
31539
|
for (const entry of entries) {
|
|
30273
|
-
const fullPath =
|
|
31540
|
+
const fullPath = join20(dirPath, entry.name);
|
|
30274
31541
|
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
30275
31542
|
continue;
|
|
30276
31543
|
}
|
|
@@ -30390,8 +31657,8 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
|
|
|
30390
31657
|
class SkillsMigrationDetector {
|
|
30391
31658
|
static async detectMigration(oldSkillsDir, currentSkillsDir) {
|
|
30392
31659
|
logger.debug("Detecting skills migration need...");
|
|
30393
|
-
const oldExists = await
|
|
30394
|
-
const currentExists = await
|
|
31660
|
+
const oldExists = await import_fs_extra12.pathExists(oldSkillsDir);
|
|
31661
|
+
const currentExists = await import_fs_extra12.pathExists(currentSkillsDir);
|
|
30395
31662
|
if (!oldExists && !currentExists) {
|
|
30396
31663
|
logger.debug("No skills directories found, migration not needed");
|
|
30397
31664
|
return {
|
|
@@ -30502,7 +31769,7 @@ class SkillsMigrationDetector {
|
|
|
30502
31769
|
};
|
|
30503
31770
|
}
|
|
30504
31771
|
static async scanDirectory(skillsDir) {
|
|
30505
|
-
if (!await
|
|
31772
|
+
if (!await import_fs_extra12.pathExists(skillsDir)) {
|
|
30506
31773
|
return ["flat", []];
|
|
30507
31774
|
}
|
|
30508
31775
|
const entries = await readdir6(skillsDir, { withFileTypes: true });
|
|
@@ -30513,12 +31780,12 @@ class SkillsMigrationDetector {
|
|
|
30513
31780
|
let totalSkillLikeCount = 0;
|
|
30514
31781
|
const allSkills = [];
|
|
30515
31782
|
for (const dir of dirs) {
|
|
30516
|
-
const dirPath =
|
|
31783
|
+
const dirPath = join21(skillsDir, dir.name);
|
|
30517
31784
|
const subEntries = await readdir6(dirPath, { withFileTypes: true });
|
|
30518
31785
|
const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
|
|
30519
31786
|
if (subdirs.length > 0) {
|
|
30520
31787
|
for (const subdir of subdirs.slice(0, 3)) {
|
|
30521
|
-
const subdirPath =
|
|
31788
|
+
const subdirPath = join21(dirPath, subdir.name);
|
|
30522
31789
|
const subdirFiles = await readdir6(subdirPath, { withFileTypes: true });
|
|
30523
31790
|
const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
|
|
30524
31791
|
if (hasSkillMarker) {
|
|
@@ -30555,16 +31822,16 @@ class SkillsMigrationDetector {
|
|
|
30555
31822
|
// src/domains/skills/skills-migrator.ts
|
|
30556
31823
|
init_logger();
|
|
30557
31824
|
init_types2();
|
|
30558
|
-
var
|
|
31825
|
+
var import_fs_extra15 = __toESM(require_lib(), 1);
|
|
30559
31826
|
import { copyFile as copyFile2, mkdir as mkdir8, readdir as readdir9, rm as rm3 } from "node:fs/promises";
|
|
30560
|
-
import { join as
|
|
31827
|
+
import { join as join24 } from "node:path";
|
|
30561
31828
|
|
|
30562
31829
|
// src/domains/skills/skills-backup-manager.ts
|
|
30563
31830
|
init_logger();
|
|
30564
31831
|
init_types2();
|
|
30565
|
-
var
|
|
30566
|
-
import { copyFile, mkdir as mkdir7, readdir as readdir7, rm as rm2, stat as
|
|
30567
|
-
import { basename as basename2, join as
|
|
31832
|
+
var import_fs_extra13 = __toESM(require_lib(), 1);
|
|
31833
|
+
import { copyFile, mkdir as mkdir7, readdir as readdir7, rm as rm2, stat as stat4 } from "node:fs/promises";
|
|
31834
|
+
import { basename as basename2, join as join22, normalize as normalize4 } from "node:path";
|
|
30568
31835
|
function validatePath(path9, paramName) {
|
|
30569
31836
|
if (!path9 || typeof path9 !== "string") {
|
|
30570
31837
|
throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
|
|
@@ -30584,13 +31851,13 @@ class SkillsBackupManager {
|
|
|
30584
31851
|
if (parentDir) {
|
|
30585
31852
|
validatePath(parentDir, "parentDir");
|
|
30586
31853
|
}
|
|
30587
|
-
if (!await
|
|
31854
|
+
if (!await import_fs_extra13.pathExists(skillsDir)) {
|
|
30588
31855
|
throw new SkillsMigrationError(`Cannot create backup: Skills directory does not exist: ${skillsDir}`);
|
|
30589
31856
|
}
|
|
30590
31857
|
const timestamp = Date.now();
|
|
30591
31858
|
const randomSuffix = Math.random().toString(36).substring(2, 8);
|
|
30592
31859
|
const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
|
|
30593
|
-
const backupDir = parentDir ?
|
|
31860
|
+
const backupDir = parentDir ? join22(parentDir, backupDirName) : join22(skillsDir, "..", backupDirName);
|
|
30594
31861
|
logger.info(`Creating backup at: ${backupDir}`);
|
|
30595
31862
|
try {
|
|
30596
31863
|
await mkdir7(backupDir, { recursive: true });
|
|
@@ -30607,12 +31874,12 @@ class SkillsBackupManager {
|
|
|
30607
31874
|
static async restoreBackup(backupDir, targetDir) {
|
|
30608
31875
|
validatePath(backupDir, "backupDir");
|
|
30609
31876
|
validatePath(targetDir, "targetDir");
|
|
30610
|
-
if (!await
|
|
31877
|
+
if (!await import_fs_extra13.pathExists(backupDir)) {
|
|
30611
31878
|
throw new SkillsMigrationError(`Cannot restore: Backup directory does not exist: ${backupDir}`);
|
|
30612
31879
|
}
|
|
30613
31880
|
logger.info(`Restoring from backup: ${backupDir}`);
|
|
30614
31881
|
try {
|
|
30615
|
-
if (await
|
|
31882
|
+
if (await import_fs_extra13.pathExists(targetDir)) {
|
|
30616
31883
|
await rm2(targetDir, { recursive: true, force: true });
|
|
30617
31884
|
}
|
|
30618
31885
|
await mkdir7(targetDir, { recursive: true });
|
|
@@ -30623,7 +31890,7 @@ class SkillsBackupManager {
|
|
|
30623
31890
|
}
|
|
30624
31891
|
}
|
|
30625
31892
|
static async deleteBackup(backupDir) {
|
|
30626
|
-
if (!await
|
|
31893
|
+
if (!await import_fs_extra13.pathExists(backupDir)) {
|
|
30627
31894
|
logger.warning(`Backup directory does not exist: ${backupDir}`);
|
|
30628
31895
|
return;
|
|
30629
31896
|
}
|
|
@@ -30636,12 +31903,12 @@ class SkillsBackupManager {
|
|
|
30636
31903
|
}
|
|
30637
31904
|
}
|
|
30638
31905
|
static async listBackups(parentDir) {
|
|
30639
|
-
if (!await
|
|
31906
|
+
if (!await import_fs_extra13.pathExists(parentDir)) {
|
|
30640
31907
|
return [];
|
|
30641
31908
|
}
|
|
30642
31909
|
try {
|
|
30643
31910
|
const entries = await readdir7(parentDir, { withFileTypes: true });
|
|
30644
|
-
const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) =>
|
|
31911
|
+
const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join22(parentDir, entry.name));
|
|
30645
31912
|
backups.sort().reverse();
|
|
30646
31913
|
return backups;
|
|
30647
31914
|
} catch (error) {
|
|
@@ -30661,7 +31928,7 @@ class SkillsBackupManager {
|
|
|
30661
31928
|
}
|
|
30662
31929
|
}
|
|
30663
31930
|
static async getBackupSize(backupDir) {
|
|
30664
|
-
if (!await
|
|
31931
|
+
if (!await import_fs_extra13.pathExists(backupDir)) {
|
|
30665
31932
|
return 0;
|
|
30666
31933
|
}
|
|
30667
31934
|
return await SkillsBackupManager.getDirectorySize(backupDir);
|
|
@@ -30669,8 +31936,8 @@ class SkillsBackupManager {
|
|
|
30669
31936
|
static async copyDirectory(sourceDir, destDir) {
|
|
30670
31937
|
const entries = await readdir7(sourceDir, { withFileTypes: true });
|
|
30671
31938
|
for (const entry of entries) {
|
|
30672
|
-
const sourcePath =
|
|
30673
|
-
const destPath =
|
|
31939
|
+
const sourcePath = join22(sourceDir, entry.name);
|
|
31940
|
+
const destPath = join22(destDir, entry.name);
|
|
30674
31941
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
|
|
30675
31942
|
continue;
|
|
30676
31943
|
}
|
|
@@ -30686,14 +31953,14 @@ class SkillsBackupManager {
|
|
|
30686
31953
|
let size = 0;
|
|
30687
31954
|
const entries = await readdir7(dirPath, { withFileTypes: true });
|
|
30688
31955
|
for (const entry of entries) {
|
|
30689
|
-
const fullPath =
|
|
31956
|
+
const fullPath = join22(dirPath, entry.name);
|
|
30690
31957
|
if (entry.isSymbolicLink()) {
|
|
30691
31958
|
continue;
|
|
30692
31959
|
}
|
|
30693
31960
|
if (entry.isDirectory()) {
|
|
30694
31961
|
size += await SkillsBackupManager.getDirectorySize(fullPath);
|
|
30695
31962
|
} else if (entry.isFile()) {
|
|
30696
|
-
const stats = await
|
|
31963
|
+
const stats = await stat4(fullPath);
|
|
30697
31964
|
size += stats.size;
|
|
30698
31965
|
}
|
|
30699
31966
|
}
|
|
@@ -30713,11 +31980,11 @@ class SkillsBackupManager {
|
|
|
30713
31980
|
// src/domains/skills/skills-customization-scanner.ts
|
|
30714
31981
|
init_logger();
|
|
30715
31982
|
init_types2();
|
|
30716
|
-
var
|
|
31983
|
+
var import_fs_extra14 = __toESM(require_lib(), 1);
|
|
30717
31984
|
import { createHash as createHash3 } from "node:crypto";
|
|
30718
31985
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
30719
|
-
import { readFile as
|
|
30720
|
-
import { join as
|
|
31986
|
+
import { readFile as readFile14, readdir as readdir8 } from "node:fs/promises";
|
|
31987
|
+
import { join as join23, normalize as normalize5, relative as relative6 } from "node:path";
|
|
30721
31988
|
function validatePath2(path9, paramName) {
|
|
30722
31989
|
if (!path9 || typeof path9 !== "string") {
|
|
30723
31990
|
throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
|
|
@@ -30796,7 +32063,7 @@ class SkillsCustomizationScanner {
|
|
|
30796
32063
|
static async detectFileChanges(currentSkillPath, baselineSkillPath) {
|
|
30797
32064
|
const changes = [];
|
|
30798
32065
|
const currentFiles = await SkillsCustomizationScanner.getAllFiles(currentSkillPath);
|
|
30799
|
-
const baselineFiles = await
|
|
32066
|
+
const baselineFiles = await import_fs_extra14.pathExists(baselineSkillPath) ? await SkillsCustomizationScanner.getAllFiles(baselineSkillPath) : [];
|
|
30800
32067
|
const currentFileMap = new Map(await Promise.all(currentFiles.map(async (f3) => {
|
|
30801
32068
|
const relPath = relative6(currentSkillPath, f3);
|
|
30802
32069
|
const hash = await SkillsCustomizationScanner.hashFile(f3);
|
|
@@ -30856,7 +32123,7 @@ class SkillsCustomizationScanner {
|
|
|
30856
32123
|
return false;
|
|
30857
32124
|
}
|
|
30858
32125
|
static async scanSkillsDirectory(skillsDir) {
|
|
30859
|
-
if (!await
|
|
32126
|
+
if (!await import_fs_extra14.pathExists(skillsDir)) {
|
|
30860
32127
|
return ["flat", []];
|
|
30861
32128
|
}
|
|
30862
32129
|
const entries = await readdir8(skillsDir, { withFileTypes: true });
|
|
@@ -30864,13 +32131,13 @@ class SkillsCustomizationScanner {
|
|
|
30864
32131
|
if (dirs.length === 0) {
|
|
30865
32132
|
return ["flat", []];
|
|
30866
32133
|
}
|
|
30867
|
-
const firstDirPath =
|
|
32134
|
+
const firstDirPath = join23(skillsDir, dirs[0].name);
|
|
30868
32135
|
const subEntries = await readdir8(firstDirPath, { withFileTypes: true });
|
|
30869
32136
|
const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
|
|
30870
32137
|
if (subdirs.length > 0) {
|
|
30871
32138
|
let skillLikeCount = 0;
|
|
30872
32139
|
for (const subdir of subdirs.slice(0, 3)) {
|
|
30873
|
-
const subdirPath =
|
|
32140
|
+
const subdirPath = join23(firstDirPath, subdir.name);
|
|
30874
32141
|
const subdirFiles = await readdir8(subdirPath, { withFileTypes: true });
|
|
30875
32142
|
const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
|
|
30876
32143
|
if (hasSkillMarker) {
|
|
@@ -30880,7 +32147,7 @@ class SkillsCustomizationScanner {
|
|
|
30880
32147
|
if (skillLikeCount > 0) {
|
|
30881
32148
|
const skills = [];
|
|
30882
32149
|
for (const dir of dirs) {
|
|
30883
|
-
const categoryPath =
|
|
32150
|
+
const categoryPath = join23(skillsDir, dir.name);
|
|
30884
32151
|
const skillDirs = await readdir8(categoryPath, { withFileTypes: true });
|
|
30885
32152
|
skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
|
|
30886
32153
|
}
|
|
@@ -30890,8 +32157,8 @@ class SkillsCustomizationScanner {
|
|
|
30890
32157
|
return ["flat", dirs.map((dir) => dir.name)];
|
|
30891
32158
|
}
|
|
30892
32159
|
static async findSkillPath(skillsDir, skillName) {
|
|
30893
|
-
const flatPath =
|
|
30894
|
-
if (await
|
|
32160
|
+
const flatPath = join23(skillsDir, skillName);
|
|
32161
|
+
if (await import_fs_extra14.pathExists(flatPath)) {
|
|
30895
32162
|
return { path: flatPath, category: undefined };
|
|
30896
32163
|
}
|
|
30897
32164
|
const entries = await readdir8(skillsDir, { withFileTypes: true });
|
|
@@ -30899,9 +32166,9 @@ class SkillsCustomizationScanner {
|
|
|
30899
32166
|
if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
30900
32167
|
continue;
|
|
30901
32168
|
}
|
|
30902
|
-
const categoryPath =
|
|
30903
|
-
const skillPath =
|
|
30904
|
-
if (await
|
|
32169
|
+
const categoryPath = join23(skillsDir, entry.name);
|
|
32170
|
+
const skillPath = join23(categoryPath, skillName);
|
|
32171
|
+
if (await import_fs_extra14.pathExists(skillPath)) {
|
|
30905
32172
|
return { path: skillPath, category: entry.name };
|
|
30906
32173
|
}
|
|
30907
32174
|
}
|
|
@@ -30911,7 +32178,7 @@ class SkillsCustomizationScanner {
|
|
|
30911
32178
|
const files = [];
|
|
30912
32179
|
const entries = await readdir8(dirPath, { withFileTypes: true });
|
|
30913
32180
|
for (const entry of entries) {
|
|
30914
|
-
const fullPath =
|
|
32181
|
+
const fullPath = join23(dirPath, entry.name);
|
|
30915
32182
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
|
|
30916
32183
|
continue;
|
|
30917
32184
|
}
|
|
@@ -30944,7 +32211,7 @@ class SkillsCustomizationScanner {
|
|
|
30944
32211
|
files.sort();
|
|
30945
32212
|
for (const file of files) {
|
|
30946
32213
|
const relativePath = relative6(dirPath, file);
|
|
30947
|
-
const content = await
|
|
32214
|
+
const content = await readFile14(file);
|
|
30948
32215
|
hash.update(relativePath);
|
|
30949
32216
|
hash.update(content);
|
|
30950
32217
|
}
|
|
@@ -31154,7 +32421,7 @@ class SkillsMigrator {
|
|
|
31154
32421
|
}
|
|
31155
32422
|
}
|
|
31156
32423
|
if (options.backup && !options.dryRun) {
|
|
31157
|
-
const claudeDir =
|
|
32424
|
+
const claudeDir = join24(currentSkillsDir, "..");
|
|
31158
32425
|
result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir);
|
|
31159
32426
|
logger.success(`Backup created at: ${result.backupPath}`);
|
|
31160
32427
|
}
|
|
@@ -31206,14 +32473,14 @@ class SkillsMigrator {
|
|
|
31206
32473
|
const migrated = [];
|
|
31207
32474
|
const preserved = [];
|
|
31208
32475
|
const errors2 = [];
|
|
31209
|
-
const tempDir =
|
|
32476
|
+
const tempDir = join24(currentSkillsDir, "..", ".skills-migration-temp");
|
|
31210
32477
|
await mkdir8(tempDir, { recursive: true });
|
|
31211
32478
|
try {
|
|
31212
32479
|
for (const mapping of mappings) {
|
|
31213
32480
|
try {
|
|
31214
32481
|
const skillName = mapping.skillName;
|
|
31215
32482
|
const currentSkillPath = mapping.oldPath;
|
|
31216
|
-
if (!await
|
|
32483
|
+
if (!await import_fs_extra15.pathExists(currentSkillPath)) {
|
|
31217
32484
|
logger.warning(`Skill not found, skipping: ${skillName}`);
|
|
31218
32485
|
continue;
|
|
31219
32486
|
}
|
|
@@ -31227,9 +32494,9 @@ class SkillsMigrator {
|
|
|
31227
32494
|
}
|
|
31228
32495
|
}
|
|
31229
32496
|
const category = mapping.category;
|
|
31230
|
-
const targetPath = category ?
|
|
32497
|
+
const targetPath = category ? join24(tempDir, category, skillName) : join24(tempDir, skillName);
|
|
31231
32498
|
if (category) {
|
|
31232
|
-
await mkdir8(
|
|
32499
|
+
await mkdir8(join24(tempDir, category), { recursive: true });
|
|
31233
32500
|
}
|
|
31234
32501
|
await SkillsMigrator.copySkillDirectory(currentSkillPath, targetPath);
|
|
31235
32502
|
migrated.push(skillName);
|
|
@@ -31263,8 +32530,8 @@ class SkillsMigrator {
|
|
|
31263
32530
|
await mkdir8(destDir, { recursive: true });
|
|
31264
32531
|
const entries = await readdir9(sourceDir, { withFileTypes: true });
|
|
31265
32532
|
for (const entry of entries) {
|
|
31266
|
-
const sourcePath =
|
|
31267
|
-
const destPath =
|
|
32533
|
+
const sourcePath = join24(sourceDir, entry.name);
|
|
32534
|
+
const destPath = join24(destDir, entry.name);
|
|
31268
32535
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
|
|
31269
32536
|
continue;
|
|
31270
32537
|
}
|
|
@@ -31852,31 +33119,31 @@ class PromptsManager {
|
|
|
31852
33119
|
|
|
31853
33120
|
// src/services/file-operations/file-scanner.ts
|
|
31854
33121
|
init_logger();
|
|
31855
|
-
import { join as
|
|
31856
|
-
var
|
|
33122
|
+
import { join as join28, relative as relative7, resolve as resolve5 } from "node:path";
|
|
33123
|
+
var import_fs_extra16 = __toESM(require_lib(), 1);
|
|
31857
33124
|
|
|
31858
33125
|
class FileScanner {
|
|
31859
33126
|
static async getFiles(dirPath, relativeTo) {
|
|
31860
33127
|
const basePath = relativeTo || dirPath;
|
|
31861
33128
|
const files = [];
|
|
31862
|
-
if (!await
|
|
33129
|
+
if (!await import_fs_extra16.pathExists(dirPath)) {
|
|
31863
33130
|
return files;
|
|
31864
33131
|
}
|
|
31865
33132
|
try {
|
|
31866
|
-
const entries = await
|
|
33133
|
+
const entries = await import_fs_extra16.readdir(dirPath, { encoding: "utf8" });
|
|
31867
33134
|
for (const entry of entries) {
|
|
31868
33135
|
if (SKIP_DIRS_ALL.includes(entry)) {
|
|
31869
33136
|
logger.debug(`Skipping directory: ${entry}`);
|
|
31870
33137
|
continue;
|
|
31871
33138
|
}
|
|
31872
|
-
const fullPath =
|
|
33139
|
+
const fullPath = join28(dirPath, entry);
|
|
31873
33140
|
if (!FileScanner.isSafePath(basePath, fullPath)) {
|
|
31874
33141
|
logger.warning(`Skipping potentially unsafe path: ${entry}`);
|
|
31875
33142
|
continue;
|
|
31876
33143
|
}
|
|
31877
33144
|
let stats;
|
|
31878
33145
|
try {
|
|
31879
|
-
stats = await
|
|
33146
|
+
stats = await import_fs_extra16.lstat(fullPath);
|
|
31880
33147
|
} catch (error) {
|
|
31881
33148
|
if (error instanceof Error && "code" in error && (error.code === "EACCES" || error.code === "EPERM")) {
|
|
31882
33149
|
logger.warning(`Skipping inaccessible path: ${entry}`);
|
|
@@ -31904,8 +33171,8 @@ class FileScanner {
|
|
|
31904
33171
|
return files;
|
|
31905
33172
|
}
|
|
31906
33173
|
static async findCustomFiles(destDir, sourceDir, subPath) {
|
|
31907
|
-
const destSubDir =
|
|
31908
|
-
const sourceSubDir =
|
|
33174
|
+
const destSubDir = join28(destDir, subPath);
|
|
33175
|
+
const sourceSubDir = join28(sourceDir, subPath);
|
|
31909
33176
|
logger.debug(`findCustomFiles - destDir: ${destDir}`);
|
|
31910
33177
|
logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
|
|
31911
33178
|
logger.debug(`findCustomFiles - subPath: "${subPath}"`);
|
|
@@ -31915,7 +33182,7 @@ class FileScanner {
|
|
|
31915
33182
|
const sourceFiles = await FileScanner.getFiles(sourceSubDir, sourceDir);
|
|
31916
33183
|
logger.debug(`findCustomFiles - destFiles count: ${destFiles.length}`);
|
|
31917
33184
|
logger.debug(`findCustomFiles - sourceFiles count: ${sourceFiles.length}`);
|
|
31918
|
-
const sourceExists = await
|
|
33185
|
+
const sourceExists = await import_fs_extra16.pathExists(sourceSubDir);
|
|
31919
33186
|
if (sourceExists && sourceFiles.length === 0 && destFiles.length > 100) {
|
|
31920
33187
|
logger.warning(`Source directory exists but is empty while destination has ${destFiles.length} files. This may indicate an extraction issue. Skipping custom file detection.`);
|
|
31921
33188
|
return [];
|
|
@@ -31943,10 +33210,10 @@ class FileScanner {
|
|
|
31943
33210
|
}
|
|
31944
33211
|
|
|
31945
33212
|
// src/services/transformers/commands-prefix.ts
|
|
31946
|
-
import { lstat as lstat3, mkdir as mkdir10, readdir as readdir11, stat as
|
|
31947
|
-
import { join as
|
|
33213
|
+
import { lstat as lstat3, mkdir as mkdir10, readdir as readdir11, stat as stat5 } from "node:fs/promises";
|
|
33214
|
+
import { join as join29 } from "node:path";
|
|
31948
33215
|
init_logger();
|
|
31949
|
-
var
|
|
33216
|
+
var import_fs_extra17 = __toESM(require_lib(), 1);
|
|
31950
33217
|
function stripWindowsDrivePrefix(path9) {
|
|
31951
33218
|
if (path9.length >= 2 && /[a-zA-Z]/.test(path9[0]) && path9[1] === ":") {
|
|
31952
33219
|
return path9.slice(2);
|
|
@@ -31985,14 +33252,14 @@ function validatePath4(path9, paramName) {
|
|
|
31985
33252
|
class CommandsPrefix {
|
|
31986
33253
|
static async applyPrefix(extractDir) {
|
|
31987
33254
|
validatePath4(extractDir, "extractDir");
|
|
31988
|
-
const commandsDir =
|
|
31989
|
-
if (!await
|
|
33255
|
+
const commandsDir = join29(extractDir, ".claude", "commands");
|
|
33256
|
+
if (!await import_fs_extra17.pathExists(commandsDir)) {
|
|
31990
33257
|
logger.verbose("No commands directory found, skipping prefix application");
|
|
31991
33258
|
return;
|
|
31992
33259
|
}
|
|
31993
33260
|
logger.info("Applying /ck: prefix to slash commands...");
|
|
31994
|
-
const backupDir =
|
|
31995
|
-
const tempDir =
|
|
33261
|
+
const backupDir = join29(extractDir, ".commands-backup");
|
|
33262
|
+
const tempDir = join29(extractDir, ".commands-prefix-temp");
|
|
31996
33263
|
try {
|
|
31997
33264
|
const entries = await readdir11(commandsDir);
|
|
31998
33265
|
if (entries.length === 0) {
|
|
@@ -32000,28 +33267,28 @@ class CommandsPrefix {
|
|
|
32000
33267
|
return;
|
|
32001
33268
|
}
|
|
32002
33269
|
if (entries.length === 1 && entries[0] === "ck") {
|
|
32003
|
-
const ckDir2 =
|
|
32004
|
-
const ckStat = await
|
|
33270
|
+
const ckDir2 = join29(commandsDir, "ck");
|
|
33271
|
+
const ckStat = await stat5(ckDir2);
|
|
32005
33272
|
if (ckStat.isDirectory()) {
|
|
32006
33273
|
logger.verbose("Commands already have /ck: prefix, skipping");
|
|
32007
33274
|
return;
|
|
32008
33275
|
}
|
|
32009
33276
|
}
|
|
32010
|
-
await
|
|
33277
|
+
await import_fs_extra17.copy(commandsDir, backupDir);
|
|
32011
33278
|
logger.verbose("Created backup of commands directory");
|
|
32012
33279
|
await mkdir10(tempDir, { recursive: true });
|
|
32013
|
-
const ckDir =
|
|
33280
|
+
const ckDir = join29(tempDir, "ck");
|
|
32014
33281
|
await mkdir10(ckDir, { recursive: true });
|
|
32015
33282
|
let processedCount = 0;
|
|
32016
33283
|
for (const entry of entries) {
|
|
32017
|
-
const sourcePath =
|
|
33284
|
+
const sourcePath = join29(commandsDir, entry);
|
|
32018
33285
|
const stats = await lstat3(sourcePath);
|
|
32019
33286
|
if (stats.isSymbolicLink()) {
|
|
32020
33287
|
logger.warning(`Skipping symlink for security: ${entry}`);
|
|
32021
33288
|
continue;
|
|
32022
33289
|
}
|
|
32023
|
-
const destPath =
|
|
32024
|
-
await
|
|
33290
|
+
const destPath = join29(ckDir, entry);
|
|
33291
|
+
await import_fs_extra17.copy(sourcePath, destPath, {
|
|
32025
33292
|
overwrite: false,
|
|
32026
33293
|
errorOnExist: true
|
|
32027
33294
|
});
|
|
@@ -32030,35 +33297,35 @@ class CommandsPrefix {
|
|
|
32030
33297
|
}
|
|
32031
33298
|
if (processedCount === 0) {
|
|
32032
33299
|
logger.warning("No files to move (all were symlinks or invalid)");
|
|
32033
|
-
await
|
|
32034
|
-
await
|
|
33300
|
+
await import_fs_extra17.remove(backupDir);
|
|
33301
|
+
await import_fs_extra17.remove(tempDir);
|
|
32035
33302
|
return;
|
|
32036
33303
|
}
|
|
32037
|
-
await
|
|
32038
|
-
await
|
|
32039
|
-
await
|
|
33304
|
+
await import_fs_extra17.remove(commandsDir);
|
|
33305
|
+
await import_fs_extra17.move(tempDir, commandsDir);
|
|
33306
|
+
await import_fs_extra17.remove(backupDir);
|
|
32040
33307
|
logger.success("Successfully applied /ck: prefix to all commands");
|
|
32041
33308
|
} catch (error) {
|
|
32042
|
-
if (await
|
|
33309
|
+
if (await import_fs_extra17.pathExists(backupDir)) {
|
|
32043
33310
|
try {
|
|
32044
|
-
await
|
|
32045
|
-
await
|
|
33311
|
+
await import_fs_extra17.remove(commandsDir).catch(() => {});
|
|
33312
|
+
await import_fs_extra17.move(backupDir, commandsDir);
|
|
32046
33313
|
logger.info("Restored original commands directory from backup");
|
|
32047
33314
|
} catch (rollbackError) {
|
|
32048
33315
|
logger.error(`Rollback failed: ${rollbackError}`);
|
|
32049
33316
|
}
|
|
32050
33317
|
}
|
|
32051
|
-
if (await
|
|
32052
|
-
await
|
|
33318
|
+
if (await import_fs_extra17.pathExists(tempDir)) {
|
|
33319
|
+
await import_fs_extra17.remove(tempDir).catch(() => {});
|
|
32053
33320
|
}
|
|
32054
33321
|
logger.error("Failed to apply /ck: prefix to commands");
|
|
32055
33322
|
throw error;
|
|
32056
33323
|
} finally {
|
|
32057
|
-
if (await
|
|
32058
|
-
await
|
|
33324
|
+
if (await import_fs_extra17.pathExists(backupDir)) {
|
|
33325
|
+
await import_fs_extra17.remove(backupDir).catch(() => {});
|
|
32059
33326
|
}
|
|
32060
|
-
if (await
|
|
32061
|
-
await
|
|
33327
|
+
if (await import_fs_extra17.pathExists(tempDir)) {
|
|
33328
|
+
await import_fs_extra17.remove(tempDir).catch(() => {});
|
|
32062
33329
|
}
|
|
32063
33330
|
}
|
|
32064
33331
|
}
|
|
@@ -32068,15 +33335,15 @@ class CommandsPrefix {
|
|
|
32068
33335
|
static async cleanupCommandsDirectory(targetDir, isGlobal, options = {}) {
|
|
32069
33336
|
const { dryRun = false, forceOverwrite = false } = options;
|
|
32070
33337
|
validatePath4(targetDir, "targetDir");
|
|
32071
|
-
const claudeDir = isGlobal ? targetDir :
|
|
32072
|
-
const commandsDir =
|
|
33338
|
+
const claudeDir = isGlobal ? targetDir : join29(targetDir, ".claude");
|
|
33339
|
+
const commandsDir = join29(claudeDir, "commands");
|
|
32073
33340
|
const result = {
|
|
32074
33341
|
results: [],
|
|
32075
33342
|
deletedCount: 0,
|
|
32076
33343
|
preservedCount: 0,
|
|
32077
33344
|
wasDryRun: dryRun
|
|
32078
33345
|
};
|
|
32079
|
-
if (!await
|
|
33346
|
+
if (!await import_fs_extra17.pathExists(commandsDir)) {
|
|
32080
33347
|
logger.verbose(`Commands directory does not exist: ${commandsDir}`);
|
|
32081
33348
|
return result;
|
|
32082
33349
|
}
|
|
@@ -32097,7 +33364,7 @@ class CommandsPrefix {
|
|
|
32097
33364
|
return result;
|
|
32098
33365
|
}
|
|
32099
33366
|
for (const entry of entries) {
|
|
32100
|
-
const entryPath =
|
|
33367
|
+
const entryPath = join29(commandsDir, entry);
|
|
32101
33368
|
const stats = await lstat3(entryPath);
|
|
32102
33369
|
if (stats.isSymbolicLink()) {
|
|
32103
33370
|
logger.warning(`Skipping symlink: ${entry}`);
|
|
@@ -32123,7 +33390,7 @@ class CommandsPrefix {
|
|
|
32123
33390
|
action: "delete"
|
|
32124
33391
|
});
|
|
32125
33392
|
if (!dryRun) {
|
|
32126
|
-
await
|
|
33393
|
+
await import_fs_extra17.remove(file);
|
|
32127
33394
|
logger.verbose(`Deleted CK file: ${relativePath}`);
|
|
32128
33395
|
}
|
|
32129
33396
|
result.deletedCount++;
|
|
@@ -32136,7 +33403,7 @@ class CommandsPrefix {
|
|
|
32136
33403
|
reason: "force overwrite"
|
|
32137
33404
|
});
|
|
32138
33405
|
if (!dryRun) {
|
|
32139
|
-
await
|
|
33406
|
+
await import_fs_extra17.remove(file);
|
|
32140
33407
|
logger.verbose(`Force-deleted modified file: ${relativePath}`);
|
|
32141
33408
|
}
|
|
32142
33409
|
result.deletedCount++;
|
|
@@ -32160,7 +33427,7 @@ class CommandsPrefix {
|
|
|
32160
33427
|
reason: "force overwrite"
|
|
32161
33428
|
});
|
|
32162
33429
|
if (!dryRun) {
|
|
32163
|
-
await
|
|
33430
|
+
await import_fs_extra17.remove(file);
|
|
32164
33431
|
logger.verbose(`Force-deleted user file: ${relativePath}`);
|
|
32165
33432
|
}
|
|
32166
33433
|
result.deletedCount++;
|
|
@@ -32178,7 +33445,7 @@ class CommandsPrefix {
|
|
|
32178
33445
|
}
|
|
32179
33446
|
}
|
|
32180
33447
|
if (canDeleteDir && !dryRun) {
|
|
32181
|
-
await
|
|
33448
|
+
await import_fs_extra17.remove(entryPath);
|
|
32182
33449
|
logger.verbose(`Removed directory: ${entry}`);
|
|
32183
33450
|
}
|
|
32184
33451
|
} else {
|
|
@@ -32191,7 +33458,7 @@ class CommandsPrefix {
|
|
|
32191
33458
|
action: "delete"
|
|
32192
33459
|
});
|
|
32193
33460
|
if (!dryRun) {
|
|
32194
|
-
await
|
|
33461
|
+
await import_fs_extra17.remove(entryPath);
|
|
32195
33462
|
logger.verbose(`Deleted CK file: ${entry}`);
|
|
32196
33463
|
}
|
|
32197
33464
|
result.deletedCount++;
|
|
@@ -32204,7 +33471,7 @@ class CommandsPrefix {
|
|
|
32204
33471
|
reason: "force overwrite"
|
|
32205
33472
|
});
|
|
32206
33473
|
if (!dryRun) {
|
|
32207
|
-
await
|
|
33474
|
+
await import_fs_extra17.remove(entryPath);
|
|
32208
33475
|
logger.verbose(`Force-deleted modified file: ${entry}`);
|
|
32209
33476
|
}
|
|
32210
33477
|
result.deletedCount++;
|
|
@@ -32227,7 +33494,7 @@ class CommandsPrefix {
|
|
|
32227
33494
|
reason: "force overwrite"
|
|
32228
33495
|
});
|
|
32229
33496
|
if (!dryRun) {
|
|
32230
|
-
await
|
|
33497
|
+
await import_fs_extra17.remove(entryPath);
|
|
32231
33498
|
logger.verbose(`Force-deleted user file: ${entry}`);
|
|
32232
33499
|
}
|
|
32233
33500
|
result.deletedCount++;
|
|
@@ -32263,7 +33530,7 @@ class CommandsPrefix {
|
|
|
32263
33530
|
const files = [];
|
|
32264
33531
|
const entries = await readdir11(dir);
|
|
32265
33532
|
for (const entry of entries) {
|
|
32266
|
-
const fullPath =
|
|
33533
|
+
const fullPath = join29(dir, entry);
|
|
32267
33534
|
const stats = await lstat3(fullPath);
|
|
32268
33535
|
if (stats.isSymbolicLink()) {
|
|
32269
33536
|
continue;
|
|
@@ -32281,9 +33548,9 @@ class CommandsPrefix {
|
|
|
32281
33548
|
// src/services/transformers/folder-path-transformer.ts
|
|
32282
33549
|
init_logger();
|
|
32283
33550
|
init_types2();
|
|
32284
|
-
var
|
|
32285
|
-
import { readFile as
|
|
32286
|
-
import { join as
|
|
33551
|
+
var import_fs_extra18 = __toESM(require_lib(), 1);
|
|
33552
|
+
import { readFile as readFile16, readdir as readdir12, rename as rename3, writeFile as writeFile14 } from "node:fs/promises";
|
|
33553
|
+
import { join as join30, relative as relative8 } from "node:path";
|
|
32287
33554
|
var TRANSFORMABLE_FILE_PATTERNS = [
|
|
32288
33555
|
".md",
|
|
32289
33556
|
".txt",
|
|
@@ -32329,34 +33596,34 @@ async function transformFolderPaths(extractDir, folders, options = {}) {
|
|
|
32329
33596
|
}
|
|
32330
33597
|
const dirsToRename = [];
|
|
32331
33598
|
if (folders.docs !== DEFAULT_FOLDERS.docs) {
|
|
32332
|
-
const docsPath =
|
|
32333
|
-
if (await
|
|
33599
|
+
const docsPath = join30(extractDir, DEFAULT_FOLDERS.docs);
|
|
33600
|
+
if (await import_fs_extra18.pathExists(docsPath)) {
|
|
32334
33601
|
dirsToRename.push({
|
|
32335
33602
|
from: docsPath,
|
|
32336
|
-
to:
|
|
33603
|
+
to: join30(extractDir, folders.docs)
|
|
32337
33604
|
});
|
|
32338
33605
|
}
|
|
32339
|
-
const claudeDocsPath =
|
|
32340
|
-
if (await
|
|
33606
|
+
const claudeDocsPath = join30(extractDir, ".claude", DEFAULT_FOLDERS.docs);
|
|
33607
|
+
if (await import_fs_extra18.pathExists(claudeDocsPath)) {
|
|
32341
33608
|
dirsToRename.push({
|
|
32342
33609
|
from: claudeDocsPath,
|
|
32343
|
-
to:
|
|
33610
|
+
to: join30(extractDir, ".claude", folders.docs)
|
|
32344
33611
|
});
|
|
32345
33612
|
}
|
|
32346
33613
|
}
|
|
32347
33614
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
32348
|
-
const plansPath =
|
|
32349
|
-
if (await
|
|
33615
|
+
const plansPath = join30(extractDir, DEFAULT_FOLDERS.plans);
|
|
33616
|
+
if (await import_fs_extra18.pathExists(plansPath)) {
|
|
32350
33617
|
dirsToRename.push({
|
|
32351
33618
|
from: plansPath,
|
|
32352
|
-
to:
|
|
33619
|
+
to: join30(extractDir, folders.plans)
|
|
32353
33620
|
});
|
|
32354
33621
|
}
|
|
32355
|
-
const claudePlansPath =
|
|
32356
|
-
if (await
|
|
33622
|
+
const claudePlansPath = join30(extractDir, ".claude", DEFAULT_FOLDERS.plans);
|
|
33623
|
+
if (await import_fs_extra18.pathExists(claudePlansPath)) {
|
|
32357
33624
|
dirsToRename.push({
|
|
32358
33625
|
from: claudePlansPath,
|
|
32359
|
-
to:
|
|
33626
|
+
to: join30(extractDir, ".claude", folders.plans)
|
|
32360
33627
|
});
|
|
32361
33628
|
}
|
|
32362
33629
|
}
|
|
@@ -32393,7 +33660,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
|
|
|
32393
33660
|
let replacementsCount = 0;
|
|
32394
33661
|
const entries = await readdir12(dir, { withFileTypes: true });
|
|
32395
33662
|
for (const entry of entries) {
|
|
32396
|
-
const fullPath =
|
|
33663
|
+
const fullPath = join30(dir, entry.name);
|
|
32397
33664
|
if (entry.isDirectory()) {
|
|
32398
33665
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
32399
33666
|
continue;
|
|
@@ -32406,7 +33673,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
|
|
|
32406
33673
|
if (!shouldTransform)
|
|
32407
33674
|
continue;
|
|
32408
33675
|
try {
|
|
32409
|
-
const content = await
|
|
33676
|
+
const content = await readFile16(fullPath, "utf-8");
|
|
32410
33677
|
let newContent = content;
|
|
32411
33678
|
let changeCount = 0;
|
|
32412
33679
|
for (const { regex: regex2, replacement } of compiledReplacements) {
|
|
@@ -32422,7 +33689,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
|
|
|
32422
33689
|
if (options.dryRun) {
|
|
32423
33690
|
logger.debug(`[dry-run] Would update ${relative8(dir, fullPath)}: ${changeCount} replacement(s)`);
|
|
32424
33691
|
} else {
|
|
32425
|
-
await
|
|
33692
|
+
await writeFile14(fullPath, newContent, "utf-8");
|
|
32426
33693
|
logger.debug(`Updated ${relative8(dir, fullPath)}: ${changeCount} replacement(s)`);
|
|
32427
33694
|
}
|
|
32428
33695
|
filesChanged++;
|
|
@@ -32502,9 +33769,9 @@ function validateFolderName(name2) {
|
|
|
32502
33769
|
|
|
32503
33770
|
// src/services/transformers/global-path-transformer.ts
|
|
32504
33771
|
init_logger();
|
|
32505
|
-
import { readFile as
|
|
33772
|
+
import { readFile as readFile17, readdir as readdir13, writeFile as writeFile15 } from "node:fs/promises";
|
|
32506
33773
|
import { platform as platform9 } from "node:os";
|
|
32507
|
-
import { extname, join as
|
|
33774
|
+
import { extname, join as join31 } from "node:path";
|
|
32508
33775
|
var IS_WINDOWS2 = platform9() === "win32";
|
|
32509
33776
|
var HOME_PREFIX = IS_WINDOWS2 ? "%USERPROFILE%" : "$HOME";
|
|
32510
33777
|
function getHomeDirPrefix() {
|
|
@@ -32596,7 +33863,7 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
|
|
|
32596
33863
|
async function processDirectory(dir) {
|
|
32597
33864
|
const entries = await readdir13(dir, { withFileTypes: true });
|
|
32598
33865
|
for (const entry of entries) {
|
|
32599
|
-
const fullPath =
|
|
33866
|
+
const fullPath = join31(dir, entry.name);
|
|
32600
33867
|
if (entry.isDirectory()) {
|
|
32601
33868
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
32602
33869
|
continue;
|
|
@@ -32604,10 +33871,10 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
|
|
|
32604
33871
|
await processDirectory(fullPath);
|
|
32605
33872
|
} else if (entry.isFile() && shouldTransformFile(entry.name)) {
|
|
32606
33873
|
try {
|
|
32607
|
-
const content = await
|
|
33874
|
+
const content = await readFile17(fullPath, "utf-8");
|
|
32608
33875
|
const { transformed, changes } = transformContent(content);
|
|
32609
33876
|
if (changes > 0) {
|
|
32610
|
-
await
|
|
33877
|
+
await writeFile15(fullPath, transformed, "utf-8");
|
|
32611
33878
|
filesTransformed++;
|
|
32612
33879
|
totalChanges += changes;
|
|
32613
33880
|
if (options.verbose) {
|
|
@@ -32638,7 +33905,7 @@ init_environment();
|
|
|
32638
33905
|
init_logger();
|
|
32639
33906
|
init_output_manager();
|
|
32640
33907
|
init_types2();
|
|
32641
|
-
var
|
|
33908
|
+
var import_fs_extra19 = __toESM(require_lib(), 1);
|
|
32642
33909
|
async function initCommand(options) {
|
|
32643
33910
|
const prompts = new PromptsManager;
|
|
32644
33911
|
prompts.intro("\uD83D\uDD27 ClaudeKit - Initialize/Update Project");
|
|
@@ -32657,8 +33924,8 @@ async function initCommand(options) {
|
|
|
32657
33924
|
const globalKitDir = PathResolver.getGlobalKitDir();
|
|
32658
33925
|
const cwdResolved = resolve6(process.cwd());
|
|
32659
33926
|
const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved === resolve6(globalKitDir, "..");
|
|
32660
|
-
const localSettingsPath =
|
|
32661
|
-
if (!isInGlobalDir && await
|
|
33927
|
+
const localSettingsPath = join32(process.cwd(), ".claude", "settings.json");
|
|
33928
|
+
if (!isInGlobalDir && await import_fs_extra19.pathExists(localSettingsPath)) {
|
|
32662
33929
|
if (isNonInteractive2) {
|
|
32663
33930
|
logger.warning("Local .claude/settings.json detected. Local settings take precedence over global.");
|
|
32664
33931
|
logger.warning("Consider removing local installation: rm -rf .claude");
|
|
@@ -32669,9 +33936,9 @@ async function initCommand(options) {
|
|
|
32669
33936
|
return;
|
|
32670
33937
|
}
|
|
32671
33938
|
if (choice === "remove") {
|
|
32672
|
-
const localClaudeDir =
|
|
33939
|
+
const localClaudeDir = join32(process.cwd(), ".claude");
|
|
32673
33940
|
try {
|
|
32674
|
-
await
|
|
33941
|
+
await import_fs_extra19.remove(localClaudeDir);
|
|
32675
33942
|
logger.success("Removed local .claude/ directory");
|
|
32676
33943
|
} catch (error) {
|
|
32677
33944
|
logger.error(`Failed to remove local installation: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -32715,7 +33982,7 @@ async function initCommand(options) {
|
|
|
32715
33982
|
}
|
|
32716
33983
|
const resolvedDir = resolve6(targetDir);
|
|
32717
33984
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
32718
|
-
if (!await
|
|
33985
|
+
if (!await import_fs_extra19.pathExists(resolvedDir)) {
|
|
32719
33986
|
if (validOptions.global) {
|
|
32720
33987
|
const { mkdir: mkdir11 } = await import("node:fs/promises");
|
|
32721
33988
|
await mkdir11(resolvedDir, { recursive: true });
|
|
@@ -32728,7 +33995,7 @@ async function initCommand(options) {
|
|
|
32728
33995
|
}
|
|
32729
33996
|
if (validOptions.fresh) {
|
|
32730
33997
|
const prefix = PathResolver.getPathPrefix(validOptions.global);
|
|
32731
|
-
const claudeDir2 = prefix ?
|
|
33998
|
+
const claudeDir2 = prefix ? join32(resolvedDir, prefix) : resolvedDir;
|
|
32732
33999
|
const canProceed = await handleFreshInstallation(claudeDir2, prompts);
|
|
32733
34000
|
if (!canProceed) {
|
|
32734
34001
|
return;
|
|
@@ -32756,7 +34023,7 @@ async function initCommand(options) {
|
|
|
32756
34023
|
logger.info("Fetching available versions...");
|
|
32757
34024
|
let currentVersion = null;
|
|
32758
34025
|
try {
|
|
32759
|
-
const metadataPath = validOptions.global ?
|
|
34026
|
+
const metadataPath = validOptions.global ? join32(PathResolver.getGlobalKitDir(), "metadata.json") : join32(resolvedDir, ".claude", "metadata.json");
|
|
32760
34027
|
const metadata = await readClaudeKitMetadata(metadataPath);
|
|
32761
34028
|
currentVersion = metadata?.version || null;
|
|
32762
34029
|
if (currentVersion) {
|
|
@@ -32881,9 +34148,9 @@ async function initCommand(options) {
|
|
|
32881
34148
|
}
|
|
32882
34149
|
}
|
|
32883
34150
|
if (!validOptions.fresh) {
|
|
32884
|
-
const newSkillsDir =
|
|
34151
|
+
const newSkillsDir = join32(extractDir, ".claude", "skills");
|
|
32885
34152
|
const currentSkillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
|
|
32886
|
-
if (await
|
|
34153
|
+
if (await import_fs_extra19.pathExists(newSkillsDir) && await import_fs_extra19.pathExists(currentSkillsDir)) {
|
|
32887
34154
|
logger.info("Checking for skills directory migration...");
|
|
32888
34155
|
const migrationDetection = await SkillsMigrationDetector.detectMigration(newSkillsDir, currentSkillsDir);
|
|
32889
34156
|
if (migrationDetection.status === "recommended" || migrationDetection.status === "required") {
|
|
@@ -32906,7 +34173,7 @@ async function initCommand(options) {
|
|
|
32906
34173
|
let customClaudeFiles = [];
|
|
32907
34174
|
if (!validOptions.fresh) {
|
|
32908
34175
|
logger.info("Scanning for custom .claude files...");
|
|
32909
|
-
const scanSourceDir = validOptions.global ?
|
|
34176
|
+
const scanSourceDir = validOptions.global ? join32(extractDir, ".claude") : extractDir;
|
|
32910
34177
|
const scanTargetSubdir = validOptions.global ? "" : ".claude";
|
|
32911
34178
|
customClaudeFiles = await FileScanner.findCustomFiles(resolvedDir, scanSourceDir, scanTargetSubdir);
|
|
32912
34179
|
} else {
|
|
@@ -32941,9 +34208,12 @@ async function initCommand(options) {
|
|
|
32941
34208
|
}
|
|
32942
34209
|
merger.setGlobalFlag(validOptions.global);
|
|
32943
34210
|
merger.setForceOverwriteSettings(validOptions.forceOverwriteSettings);
|
|
32944
|
-
const claudeDir = validOptions.global ? resolvedDir :
|
|
34211
|
+
const claudeDir = validOptions.global ? resolvedDir : join32(resolvedDir, ".claude");
|
|
32945
34212
|
const releaseManifest = await ReleaseManifestLoader.load(extractDir);
|
|
32946
|
-
if (
|
|
34213
|
+
if (releaseManifest) {
|
|
34214
|
+
merger.setManifest(releaseManifest);
|
|
34215
|
+
}
|
|
34216
|
+
if (!validOptions.fresh && await import_fs_extra19.pathExists(claudeDir)) {
|
|
32947
34217
|
const legacyDetection = await LegacyMigration.detectLegacy(claudeDir);
|
|
32948
34218
|
if (legacyDetection.isLegacy && releaseManifest) {
|
|
32949
34219
|
logger.info("Legacy installation detected - migrating to ownership tracking...");
|
|
@@ -32963,7 +34233,7 @@ async function initCommand(options) {
|
|
|
32963
34233
|
return;
|
|
32964
34234
|
}
|
|
32965
34235
|
}
|
|
32966
|
-
const sourceDir = validOptions.global ?
|
|
34236
|
+
const sourceDir = validOptions.global ? join32(extractDir, ".claude") : extractDir;
|
|
32967
34237
|
await merger.merge(sourceDir, resolvedDir, false);
|
|
32968
34238
|
const manifestWriter = new ManifestWriter;
|
|
32969
34239
|
const installedFiles = merger.getAllInstalledFiles();
|
|
@@ -32972,7 +34242,7 @@ async function initCommand(options) {
|
|
|
32972
34242
|
if (!validOptions.global && !installedPath.startsWith(".claude/"))
|
|
32973
34243
|
continue;
|
|
32974
34244
|
const relativePath = validOptions.global ? installedPath : installedPath.replace(/^\.claude\//, "");
|
|
32975
|
-
const filePath =
|
|
34245
|
+
const filePath = join32(claudeDir, relativePath);
|
|
32976
34246
|
const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
|
|
32977
34247
|
const ownership = manifestEntry ? "ck" : "user";
|
|
32978
34248
|
filesToTrack.push({
|
|
@@ -32991,13 +34261,13 @@ async function initCommand(options) {
|
|
|
32991
34261
|
}
|
|
32992
34262
|
});
|
|
32993
34263
|
trackingSpinner.succeed(`Tracked ${trackResult.success} files`);
|
|
32994
|
-
await manifestWriter.writeManifest(claudeDir, kitConfig.name, release.tag_name, validOptions.global ? "global" : "local");
|
|
34264
|
+
await manifestWriter.writeManifest(claudeDir, kitConfig.name, release.tag_name, validOptions.global ? "global" : "local", kit);
|
|
32995
34265
|
if (validOptions.global) {
|
|
32996
|
-
const claudeMdSource =
|
|
32997
|
-
const claudeMdDest =
|
|
32998
|
-
if (await
|
|
32999
|
-
if (!await
|
|
33000
|
-
await
|
|
34266
|
+
const claudeMdSource = join32(extractDir, "CLAUDE.md");
|
|
34267
|
+
const claudeMdDest = join32(resolvedDir, "CLAUDE.md");
|
|
34268
|
+
if (await import_fs_extra19.pathExists(claudeMdSource)) {
|
|
34269
|
+
if (!await import_fs_extra19.pathExists(claudeMdDest)) {
|
|
34270
|
+
await import_fs_extra19.copy(claudeMdSource, claudeMdDest);
|
|
33001
34271
|
logger.success("Copied CLAUDE.md to global directory");
|
|
33002
34272
|
} else {
|
|
33003
34273
|
logger.debug("CLAUDE.md already exists in global directory (preserved)");
|
|
@@ -33017,18 +34287,27 @@ async function initCommand(options) {
|
|
|
33017
34287
|
const { isGeminiInstalled: isGeminiInstalled2 } = await Promise.resolve().then(() => (init_package_installer(), exports_package_installer));
|
|
33018
34288
|
const { checkExistingGeminiConfig: checkExistingGeminiConfig2, findMcpConfigPath: findMcpConfigPath2, processGeminiMcpLinking: processGeminiMcpLinking2 } = await Promise.resolve().then(() => (init_gemini_mcp_linker(), exports_gemini_mcp_linker));
|
|
33019
34289
|
const geminiInstalled = await isGeminiInstalled2();
|
|
33020
|
-
const existingConfig = checkExistingGeminiConfig2(resolvedDir);
|
|
33021
|
-
const
|
|
34290
|
+
const existingConfig = checkExistingGeminiConfig2(resolvedDir, validOptions.global);
|
|
34291
|
+
const mcpConfigPath = findMcpConfigPath2(resolvedDir);
|
|
34292
|
+
const mcpConfigExists = mcpConfigPath !== null;
|
|
33022
34293
|
if (geminiInstalled && !existingConfig.exists && mcpConfigExists) {
|
|
33023
|
-
const
|
|
34294
|
+
const geminiPath = validOptions.global ? "~/.gemini/settings.json" : ".gemini/settings.json";
|
|
34295
|
+
const mcpPath = validOptions.global ? "~/.claude/.mcp.json" : ".mcp.json";
|
|
34296
|
+
const promptMessage = [
|
|
34297
|
+
"Gemini CLI detected. Set up MCP integration?",
|
|
34298
|
+
` → Creates ${geminiPath} symlink to ${mcpPath}`,
|
|
34299
|
+
" → Gemini CLI will share MCP servers with Claude Code"
|
|
34300
|
+
].join(`
|
|
34301
|
+
`);
|
|
34302
|
+
const shouldSetupGemini = await prompts.confirm(promptMessage);
|
|
33024
34303
|
if (shouldSetupGemini) {
|
|
33025
|
-
await processGeminiMcpLinking2(resolvedDir);
|
|
34304
|
+
await processGeminiMcpLinking2(resolvedDir, { isGlobal: validOptions.global });
|
|
33026
34305
|
}
|
|
33027
34306
|
}
|
|
33028
34307
|
}
|
|
33029
34308
|
if (!validOptions.skipSetup && !isNonInteractive2) {
|
|
33030
|
-
const envPath =
|
|
33031
|
-
if (!await
|
|
34309
|
+
const envPath = join32(claudeDir, ".env");
|
|
34310
|
+
if (!await import_fs_extra19.pathExists(envPath)) {
|
|
33032
34311
|
const shouldSetup = await prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
|
|
33033
34312
|
if (shouldSetup) {
|
|
33034
34313
|
await runSetupWizard({
|
|
@@ -33058,13 +34337,13 @@ Protected files (.env, etc.) were not modified.`;
|
|
|
33058
34337
|
}
|
|
33059
34338
|
|
|
33060
34339
|
// src/commands/new.ts
|
|
33061
|
-
import { join as
|
|
34340
|
+
import { join as join33, resolve as resolve7 } from "node:path";
|
|
33062
34341
|
init_package_installer();
|
|
33063
34342
|
init_environment();
|
|
33064
34343
|
init_logger();
|
|
33065
34344
|
init_output_manager();
|
|
33066
34345
|
init_types2();
|
|
33067
|
-
var
|
|
34346
|
+
var import_fs_extra20 = __toESM(require_lib(), 1);
|
|
33068
34347
|
async function newCommand(options) {
|
|
33069
34348
|
const prompts = new PromptsManager;
|
|
33070
34349
|
prompts.intro("\uD83D\uDE80 ClaudeKit - Create New Project");
|
|
@@ -33091,8 +34370,8 @@ async function newCommand(options) {
|
|
|
33091
34370
|
}
|
|
33092
34371
|
const resolvedDir = resolve7(targetDir);
|
|
33093
34372
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
33094
|
-
if (await
|
|
33095
|
-
const files = await
|
|
34373
|
+
if (await import_fs_extra20.pathExists(resolvedDir)) {
|
|
34374
|
+
const files = await import_fs_extra20.readdir(resolvedDir);
|
|
33096
34375
|
const isEmpty = files.length === 0;
|
|
33097
34376
|
if (!isEmpty) {
|
|
33098
34377
|
if (isNonInteractive2) {
|
|
@@ -33239,7 +34518,7 @@ async function newCommand(options) {
|
|
|
33239
34518
|
await CommandsPrefix.cleanupCommandsDirectory(resolvedDir, false);
|
|
33240
34519
|
}
|
|
33241
34520
|
await merger.merge(extractDir, resolvedDir, true);
|
|
33242
|
-
const claudeDir =
|
|
34521
|
+
const claudeDir = join33(resolvedDir, ".claude");
|
|
33243
34522
|
const manifestWriter = new ManifestWriter;
|
|
33244
34523
|
const releaseManifest = await ReleaseManifestLoader.load(extractDir);
|
|
33245
34524
|
const installedFiles = merger.getAllInstalledFiles();
|
|
@@ -33248,7 +34527,7 @@ async function newCommand(options) {
|
|
|
33248
34527
|
if (!installedPath.startsWith(".claude/"))
|
|
33249
34528
|
continue;
|
|
33250
34529
|
const relativePath = installedPath.replace(/^\.claude\//, "");
|
|
33251
|
-
const filePath =
|
|
34530
|
+
const filePath = join33(claudeDir, relativePath);
|
|
33252
34531
|
const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
|
|
33253
34532
|
const ownership = manifestEntry ? "ck" : "user";
|
|
33254
34533
|
filesToTrack.push({
|
|
@@ -33301,10 +34580,10 @@ async function newCommand(options) {
|
|
|
33301
34580
|
|
|
33302
34581
|
// src/commands/uninstall.ts
|
|
33303
34582
|
import { readdirSync, rmSync } from "node:fs";
|
|
33304
|
-
import { dirname as dirname7, join as
|
|
34583
|
+
import { dirname as dirname7, join as join34 } from "node:path";
|
|
33305
34584
|
init_logger();
|
|
33306
34585
|
init_types2();
|
|
33307
|
-
var
|
|
34586
|
+
var import_fs_extra21 = __toESM(require_lib(), 1);
|
|
33308
34587
|
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
33309
34588
|
async function detectInstallations() {
|
|
33310
34589
|
const installations = [];
|
|
@@ -33313,14 +34592,14 @@ async function detectInstallations() {
|
|
|
33313
34592
|
installations.push({
|
|
33314
34593
|
type: "local",
|
|
33315
34594
|
path: setup.project.path,
|
|
33316
|
-
exists: await
|
|
34595
|
+
exists: await import_fs_extra21.pathExists(setup.project.path)
|
|
33317
34596
|
});
|
|
33318
34597
|
}
|
|
33319
34598
|
if (setup.global.path && setup.global.metadata) {
|
|
33320
34599
|
installations.push({
|
|
33321
34600
|
type: "global",
|
|
33322
34601
|
path: setup.global.path,
|
|
33323
|
-
exists: await
|
|
34602
|
+
exists: await import_fs_extra21.pathExists(setup.global.path)
|
|
33324
34603
|
});
|
|
33325
34604
|
}
|
|
33326
34605
|
return installations.filter((i) => i.exists);
|
|
@@ -33353,14 +34632,26 @@ async function promptScope(installations) {
|
|
|
33353
34632
|
}
|
|
33354
34633
|
return selected;
|
|
33355
34634
|
}
|
|
33356
|
-
async function confirmUninstall(scope) {
|
|
34635
|
+
async function confirmUninstall(scope, kitLabel = "") {
|
|
33357
34636
|
const scopeText = scope === "all" ? "all ClaudeKit installations" : scope === "local" ? "local ClaudeKit installation" : "global ClaudeKit installation";
|
|
33358
34637
|
const confirmed = await se({
|
|
33359
|
-
message: `Continue with uninstalling ${scopeText}?`,
|
|
34638
|
+
message: `Continue with uninstalling ${scopeText}${kitLabel}?`,
|
|
33360
34639
|
initialValue: false
|
|
33361
34640
|
});
|
|
33362
34641
|
return confirmed === true;
|
|
33363
34642
|
}
|
|
34643
|
+
function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
|
|
34644
|
+
if (ownership === "ck") {
|
|
34645
|
+
return { action: "delete", reason: deleteReason };
|
|
34646
|
+
}
|
|
34647
|
+
if (ownership === "ck-modified") {
|
|
34648
|
+
if (forceOverwrite) {
|
|
34649
|
+
return { action: "delete", reason: "force overwrite" };
|
|
34650
|
+
}
|
|
34651
|
+
return { action: "preserve", reason: "modified by user" };
|
|
34652
|
+
}
|
|
34653
|
+
return { action: "preserve", reason: "user-created" };
|
|
34654
|
+
}
|
|
33364
34655
|
async function cleanupEmptyDirectories(filePath, installationRoot) {
|
|
33365
34656
|
let cleaned = 0;
|
|
33366
34657
|
let currentDir = dirname7(filePath);
|
|
@@ -33381,33 +34672,56 @@ async function cleanupEmptyDirectories(filePath, installationRoot) {
|
|
|
33381
34672
|
}
|
|
33382
34673
|
return cleaned;
|
|
33383
34674
|
}
|
|
33384
|
-
async function analyzeInstallation(installation, forceOverwrite) {
|
|
33385
|
-
const result = {
|
|
34675
|
+
async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
34676
|
+
const result = {
|
|
34677
|
+
toDelete: [],
|
|
34678
|
+
toPreserve: [],
|
|
34679
|
+
remainingKits: []
|
|
34680
|
+
};
|
|
33386
34681
|
const metadata = await ManifestWriter.readManifest(installation.path);
|
|
34682
|
+
const uninstallManifest = await ManifestWriter.getUninstallManifest(installation.path, kit);
|
|
34683
|
+
result.remainingKits = uninstallManifest.remainingKits;
|
|
34684
|
+
if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
|
|
34685
|
+
const kitFiles = metadata.kits[kit].files || [];
|
|
34686
|
+
for (const trackedFile of kitFiles) {
|
|
34687
|
+
const filePath = join34(installation.path, trackedFile.path);
|
|
34688
|
+
if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
|
|
34689
|
+
result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
|
|
34690
|
+
continue;
|
|
34691
|
+
}
|
|
34692
|
+
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
34693
|
+
if (!ownershipResult.exists)
|
|
34694
|
+
continue;
|
|
34695
|
+
const classification = classifyFileByOwnership(ownershipResult.ownership, forceOverwrite, `${kit} kit (pristine)`);
|
|
34696
|
+
if (classification.action === "delete") {
|
|
34697
|
+
result.toDelete.push({ path: trackedFile.path, reason: classification.reason });
|
|
34698
|
+
} else {
|
|
34699
|
+
result.toPreserve.push({ path: trackedFile.path, reason: classification.reason });
|
|
34700
|
+
}
|
|
34701
|
+
}
|
|
34702
|
+
if (result.remainingKits.length === 0) {
|
|
34703
|
+
result.toDelete.push({ path: "metadata.json", reason: "metadata file" });
|
|
34704
|
+
}
|
|
34705
|
+
return result;
|
|
34706
|
+
}
|
|
33387
34707
|
if (!metadata?.files || metadata.files.length === 0) {
|
|
33388
|
-
const
|
|
33389
|
-
|
|
33390
|
-
if (!filesToPreserve.includes(item)) {
|
|
34708
|
+
for (const item of uninstallManifest.filesToRemove) {
|
|
34709
|
+
if (!uninstallManifest.filesToPreserve.includes(item)) {
|
|
33391
34710
|
result.toDelete.push({ path: item, reason: "legacy installation" });
|
|
33392
34711
|
}
|
|
33393
34712
|
}
|
|
33394
34713
|
return result;
|
|
33395
34714
|
}
|
|
33396
|
-
for (const trackedFile of metadata.files) {
|
|
33397
|
-
const filePath =
|
|
34715
|
+
for (const trackedFile of metadata.files || []) {
|
|
34716
|
+
const filePath = join34(installation.path, trackedFile.path);
|
|
33398
34717
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
33399
34718
|
if (!ownershipResult.exists)
|
|
33400
34719
|
continue;
|
|
33401
|
-
|
|
33402
|
-
|
|
33403
|
-
|
|
33404
|
-
if (forceOverwrite) {
|
|
33405
|
-
result.toDelete.push({ path: trackedFile.path, reason: "force overwrite" });
|
|
33406
|
-
} else {
|
|
33407
|
-
result.toPreserve.push({ path: trackedFile.path, reason: "modified by user" });
|
|
33408
|
-
}
|
|
34720
|
+
const classification = classifyFileByOwnership(ownershipResult.ownership, forceOverwrite, "CK-owned (pristine)");
|
|
34721
|
+
if (classification.action === "delete") {
|
|
34722
|
+
result.toDelete.push({ path: trackedFile.path, reason: classification.reason });
|
|
33409
34723
|
} else {
|
|
33410
|
-
result.toPreserve.push({ path: trackedFile.path, reason:
|
|
34724
|
+
result.toPreserve.push({ path: trackedFile.path, reason: classification.reason });
|
|
33411
34725
|
}
|
|
33412
34726
|
}
|
|
33413
34727
|
result.toDelete.push({ path: "metadata.json", reason: "metadata file" });
|
|
@@ -33442,24 +34756,32 @@ function displayDryRunPreview(analysis, installationType) {
|
|
|
33442
34756
|
}
|
|
33443
34757
|
async function removeInstallations(installations, options) {
|
|
33444
34758
|
for (const installation of installations) {
|
|
33445
|
-
const analysis = await analyzeInstallation(installation, options.forceOverwrite);
|
|
34759
|
+
const analysis = await analyzeInstallation(installation, options.forceOverwrite, options.kit);
|
|
33446
34760
|
if (options.dryRun) {
|
|
33447
|
-
|
|
34761
|
+
const label = options.kit ? `${installation.type} (${options.kit} kit)` : installation.type;
|
|
34762
|
+
displayDryRunPreview(analysis, label);
|
|
34763
|
+
if (analysis.remainingKits.length > 0) {
|
|
34764
|
+
log.info(`Remaining kits after uninstall: ${analysis.remainingKits.join(", ")}`);
|
|
34765
|
+
}
|
|
33448
34766
|
continue;
|
|
33449
34767
|
}
|
|
33450
|
-
const
|
|
34768
|
+
const kitLabel = options.kit ? ` ${options.kit} kit` : "";
|
|
34769
|
+
const spinner = createSpinner(`Removing ${installation.type}${kitLabel} ClaudeKit files...`).start();
|
|
33451
34770
|
try {
|
|
33452
34771
|
let removedCount = 0;
|
|
33453
34772
|
let cleanedDirs = 0;
|
|
33454
34773
|
for (const item of analysis.toDelete) {
|
|
33455
|
-
const filePath =
|
|
33456
|
-
if (await
|
|
33457
|
-
await
|
|
34774
|
+
const filePath = join34(installation.path, item.path);
|
|
34775
|
+
if (await import_fs_extra21.pathExists(filePath)) {
|
|
34776
|
+
await import_fs_extra21.remove(filePath);
|
|
33458
34777
|
removedCount++;
|
|
33459
34778
|
logger.debug(`Removed: ${item.path}`);
|
|
33460
34779
|
cleanedDirs += await cleanupEmptyDirectories(filePath, installation.path);
|
|
33461
34780
|
}
|
|
33462
34781
|
}
|
|
34782
|
+
if (options.kit && analysis.remainingKits.length > 0) {
|
|
34783
|
+
await ManifestWriter.removeKitFromManifest(installation.path, options.kit);
|
|
34784
|
+
}
|
|
33463
34785
|
try {
|
|
33464
34786
|
const remaining = readdirSync(installation.path);
|
|
33465
34787
|
if (remaining.length === 0) {
|
|
@@ -33467,7 +34789,8 @@ async function removeInstallations(installations, options) {
|
|
|
33467
34789
|
logger.debug(`Removed empty installation directory: ${installation.path}`);
|
|
33468
34790
|
}
|
|
33469
34791
|
} catch {}
|
|
33470
|
-
|
|
34792
|
+
const kitsInfo = analysis.remainingKits.length > 0 ? `, ${analysis.remainingKits.join(", ")} kit(s) preserved` : "";
|
|
34793
|
+
spinner.succeed(`Removed ${removedCount} files${cleanedDirs > 0 ? `, cleaned ${cleanedDirs} empty directories` : ""}, preserved ${analysis.toPreserve.length} customizations${kitsInfo}`);
|
|
33471
34794
|
if (analysis.toPreserve.length > 0) {
|
|
33472
34795
|
log.info("Preserved customizations:");
|
|
33473
34796
|
analysis.toPreserve.slice(0, 5).forEach((f3) => log.message(` - ${f3.path} (${f3.reason})`));
|
|
@@ -33489,6 +34812,23 @@ async function uninstallCommand(options) {
|
|
|
33489
34812
|
logger.info("No ClaudeKit installations found.");
|
|
33490
34813
|
return;
|
|
33491
34814
|
}
|
|
34815
|
+
if (validOptions.kit) {
|
|
34816
|
+
let kitFound = false;
|
|
34817
|
+
for (const inst of allInstallations) {
|
|
34818
|
+
const metadata = await ManifestWriter.readManifest(inst.path);
|
|
34819
|
+
if (metadata) {
|
|
34820
|
+
const installedKits = getInstalledKits(metadata);
|
|
34821
|
+
if (installedKits.includes(validOptions.kit)) {
|
|
34822
|
+
kitFound = true;
|
|
34823
|
+
break;
|
|
34824
|
+
}
|
|
34825
|
+
}
|
|
34826
|
+
}
|
|
34827
|
+
if (!kitFound) {
|
|
34828
|
+
logger.info(`Kit "${validOptions.kit}" is not installed.`);
|
|
34829
|
+
return;
|
|
34830
|
+
}
|
|
34831
|
+
}
|
|
33492
34832
|
let scope;
|
|
33493
34833
|
if (validOptions.all || validOptions.local && validOptions.global) {
|
|
33494
34834
|
scope = "all";
|
|
@@ -33515,11 +34855,15 @@ async function uninstallCommand(options) {
|
|
|
33515
34855
|
return;
|
|
33516
34856
|
}
|
|
33517
34857
|
displayInstallations(installations, scope);
|
|
34858
|
+
if (validOptions.kit) {
|
|
34859
|
+
log.info(import_picocolors13.default.cyan(`Kit-scoped uninstall: ${validOptions.kit} kit only`));
|
|
34860
|
+
}
|
|
33518
34861
|
if (validOptions.dryRun) {
|
|
33519
34862
|
log.info(import_picocolors13.default.yellow("DRY RUN MODE - No files will be deleted"));
|
|
33520
34863
|
await removeInstallations(installations, {
|
|
33521
34864
|
dryRun: true,
|
|
33522
|
-
forceOverwrite: validOptions.forceOverwrite
|
|
34865
|
+
forceOverwrite: validOptions.forceOverwrite,
|
|
34866
|
+
kit: validOptions.kit
|
|
33523
34867
|
});
|
|
33524
34868
|
outro("Dry-run complete. No changes were made.");
|
|
33525
34869
|
return;
|
|
@@ -33529,7 +34873,8 @@ async function uninstallCommand(options) {
|
|
|
33529
34873
|
${import_picocolors13.default.yellow("User modifications will be permanently deleted!")}`);
|
|
33530
34874
|
}
|
|
33531
34875
|
if (!validOptions.yes) {
|
|
33532
|
-
const
|
|
34876
|
+
const kitLabel = validOptions.kit ? ` (${validOptions.kit} kit only)` : "";
|
|
34877
|
+
const confirmed = await confirmUninstall(scope, kitLabel);
|
|
33533
34878
|
if (!confirmed) {
|
|
33534
34879
|
logger.info("Uninstall cancelled.");
|
|
33535
34880
|
return;
|
|
@@ -33537,9 +34882,11 @@ ${import_picocolors13.default.yellow("User modifications will be permanently del
|
|
|
33537
34882
|
}
|
|
33538
34883
|
await removeInstallations(installations, {
|
|
33539
34884
|
dryRun: false,
|
|
33540
|
-
forceOverwrite: validOptions.forceOverwrite
|
|
34885
|
+
forceOverwrite: validOptions.forceOverwrite,
|
|
34886
|
+
kit: validOptions.kit
|
|
33541
34887
|
});
|
|
33542
|
-
|
|
34888
|
+
const kitMsg = validOptions.kit ? ` (${validOptions.kit} kit)` : "";
|
|
34889
|
+
outro(`ClaudeKit${kitMsg} uninstalled successfully!`);
|
|
33543
34890
|
} catch (error) {
|
|
33544
34891
|
logger.error(error instanceof Error ? error.message : "Unknown error");
|
|
33545
34892
|
process.exit(1);
|
|
@@ -33693,7 +35040,7 @@ var import_compare_versions2 = __toESM(require_umd(), 1);
|
|
|
33693
35040
|
// package.json
|
|
33694
35041
|
var package_default2 = {
|
|
33695
35042
|
name: "claudekit-cli",
|
|
33696
|
-
version: "3.
|
|
35043
|
+
version: "3.11.0",
|
|
33697
35044
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
33698
35045
|
type: "module",
|
|
33699
35046
|
repository: {
|
|
@@ -33713,7 +35060,7 @@ var package_default2 = {
|
|
|
33713
35060
|
],
|
|
33714
35061
|
scripts: {
|
|
33715
35062
|
dev: "bun run src/index.ts",
|
|
33716
|
-
build: "bun build src/index.ts --outdir dist --target node --external
|
|
35063
|
+
build: "bun build src/index.ts --outdir dist --target node --external @octokit/rest",
|
|
33717
35064
|
compile: "bun build src/index.ts --compile --outfile ck",
|
|
33718
35065
|
"compile:binary": "bun build src/index.ts --compile --outfile bin/ck",
|
|
33719
35066
|
"compile:binaries": "node scripts/build-all-binaries.js",
|
|
@@ -33754,11 +35101,11 @@ var package_default2 = {
|
|
|
33754
35101
|
"extract-zip": "^2.0.1",
|
|
33755
35102
|
"fs-extra": "^11.2.0",
|
|
33756
35103
|
ignore: "^5.3.2",
|
|
33757
|
-
keytar: "^7.9.0",
|
|
33758
35104
|
minimatch: "^10.1.1",
|
|
33759
35105
|
ora: "^8.0.0",
|
|
33760
35106
|
"p-limit": "^7.2.0",
|
|
33761
35107
|
picocolors: "^1.1.1",
|
|
35108
|
+
"proper-lockfile": "^4.1.2",
|
|
33762
35109
|
tar: "^7.4.3",
|
|
33763
35110
|
tmp: "^0.2.3",
|
|
33764
35111
|
zod: "^3.23.8"
|
|
@@ -33771,6 +35118,7 @@ var package_default2 = {
|
|
|
33771
35118
|
"@types/cli-progress": "^3.11.6",
|
|
33772
35119
|
"@types/fs-extra": "^11.0.4",
|
|
33773
35120
|
"@types/node": "^22.10.1",
|
|
35121
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
33774
35122
|
"@types/tar": "^6.1.13",
|
|
33775
35123
|
"@types/tmp": "^0.2.6",
|
|
33776
35124
|
"semantic-release": "^24.2.0",
|
|
@@ -34001,14 +35349,14 @@ var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
|
34001
35349
|
// src/domains/versioning/version-cache.ts
|
|
34002
35350
|
init_logger();
|
|
34003
35351
|
import { existsSync as existsSync8 } from "node:fs";
|
|
34004
|
-
import { mkdir as mkdir11, readFile as
|
|
34005
|
-
import { join as
|
|
35352
|
+
import { mkdir as mkdir11, readFile as readFile18, writeFile as writeFile16 } from "node:fs/promises";
|
|
35353
|
+
import { join as join35 } from "node:path";
|
|
34006
35354
|
class VersionCacheManager {
|
|
34007
35355
|
static CACHE_FILENAME = "version-check.json";
|
|
34008
35356
|
static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
34009
35357
|
static getCacheFile() {
|
|
34010
35358
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
34011
|
-
return
|
|
35359
|
+
return join35(cacheDir, VersionCacheManager.CACHE_FILENAME);
|
|
34012
35360
|
}
|
|
34013
35361
|
static async load() {
|
|
34014
35362
|
const cacheFile = VersionCacheManager.getCacheFile();
|
|
@@ -34017,7 +35365,7 @@ class VersionCacheManager {
|
|
|
34017
35365
|
logger.debug("Version check cache not found");
|
|
34018
35366
|
return null;
|
|
34019
35367
|
}
|
|
34020
|
-
const content = await
|
|
35368
|
+
const content = await readFile18(cacheFile, "utf-8");
|
|
34021
35369
|
const cache2 = JSON.parse(content);
|
|
34022
35370
|
if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
|
|
34023
35371
|
logger.debug("Invalid cache structure, ignoring");
|
|
@@ -34037,7 +35385,7 @@ class VersionCacheManager {
|
|
|
34037
35385
|
if (!existsSync8(cacheDir)) {
|
|
34038
35386
|
await mkdir11(cacheDir, { recursive: true, mode: 448 });
|
|
34039
35387
|
}
|
|
34040
|
-
await
|
|
35388
|
+
await writeFile16(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
|
|
34041
35389
|
logger.debug(`Version check cache saved to ${cacheFile}`);
|
|
34042
35390
|
} catch (error) {
|
|
34043
35391
|
logger.debug(`Failed to save version check cache: ${error}`);
|
|
@@ -34520,7 +35868,7 @@ var output2 = new OutputManager2;
|
|
|
34520
35868
|
|
|
34521
35869
|
// src/shared/path-resolver.ts
|
|
34522
35870
|
import { homedir as homedir5, platform as platform10 } from "node:os";
|
|
34523
|
-
import { join as
|
|
35871
|
+
import { join as join36, normalize as normalize6 } from "node:path";
|
|
34524
35872
|
|
|
34525
35873
|
class PathResolver2 {
|
|
34526
35874
|
static getTestHomeDir() {
|
|
@@ -34553,50 +35901,50 @@ class PathResolver2 {
|
|
|
34553
35901
|
static getConfigDir(global3 = false) {
|
|
34554
35902
|
const testHome = PathResolver2.getTestHomeDir();
|
|
34555
35903
|
if (testHome) {
|
|
34556
|
-
return global3 ?
|
|
35904
|
+
return global3 ? join36(testHome, ".config", "claude") : join36(testHome, ".claudekit");
|
|
34557
35905
|
}
|
|
34558
35906
|
if (!global3) {
|
|
34559
|
-
return
|
|
35907
|
+
return join36(homedir5(), ".claudekit");
|
|
34560
35908
|
}
|
|
34561
35909
|
const os2 = platform10();
|
|
34562
35910
|
if (os2 === "win32") {
|
|
34563
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
34564
|
-
return
|
|
35911
|
+
const localAppData = process.env.LOCALAPPDATA || join36(homedir5(), "AppData", "Local");
|
|
35912
|
+
return join36(localAppData, "claude");
|
|
34565
35913
|
}
|
|
34566
35914
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
34567
35915
|
if (xdgConfigHome) {
|
|
34568
|
-
return
|
|
35916
|
+
return join36(xdgConfigHome, "claude");
|
|
34569
35917
|
}
|
|
34570
|
-
return
|
|
35918
|
+
return join36(homedir5(), ".config", "claude");
|
|
34571
35919
|
}
|
|
34572
35920
|
static getConfigFile(global3 = false) {
|
|
34573
|
-
return
|
|
35921
|
+
return join36(PathResolver2.getConfigDir(global3), "config.json");
|
|
34574
35922
|
}
|
|
34575
35923
|
static getCacheDir(global3 = false) {
|
|
34576
35924
|
const testHome = PathResolver2.getTestHomeDir();
|
|
34577
35925
|
if (testHome) {
|
|
34578
|
-
return global3 ?
|
|
35926
|
+
return global3 ? join36(testHome, ".cache", "claude") : join36(testHome, ".claudekit", "cache");
|
|
34579
35927
|
}
|
|
34580
35928
|
if (!global3) {
|
|
34581
|
-
return
|
|
35929
|
+
return join36(homedir5(), ".claudekit", "cache");
|
|
34582
35930
|
}
|
|
34583
35931
|
const os2 = platform10();
|
|
34584
35932
|
if (os2 === "win32") {
|
|
34585
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
34586
|
-
return
|
|
35933
|
+
const localAppData = process.env.LOCALAPPDATA || join36(homedir5(), "AppData", "Local");
|
|
35934
|
+
return join36(localAppData, "claude", "cache");
|
|
34587
35935
|
}
|
|
34588
35936
|
const xdgCacheHome = process.env.XDG_CACHE_HOME;
|
|
34589
35937
|
if (xdgCacheHome) {
|
|
34590
|
-
return
|
|
35938
|
+
return join36(xdgCacheHome, "claude");
|
|
34591
35939
|
}
|
|
34592
|
-
return
|
|
35940
|
+
return join36(homedir5(), ".cache", "claude");
|
|
34593
35941
|
}
|
|
34594
35942
|
static getGlobalKitDir() {
|
|
34595
35943
|
const testHome = PathResolver2.getTestHomeDir();
|
|
34596
35944
|
if (testHome) {
|
|
34597
|
-
return
|
|
35945
|
+
return join36(testHome, ".claude");
|
|
34598
35946
|
}
|
|
34599
|
-
return
|
|
35947
|
+
return join36(homedir5(), ".claude");
|
|
34600
35948
|
}
|
|
34601
35949
|
static getPathPrefix(global3) {
|
|
34602
35950
|
return global3 ? "" : ".claude";
|
|
@@ -34604,9 +35952,9 @@ class PathResolver2 {
|
|
|
34604
35952
|
static buildSkillsPath(baseDir, global3) {
|
|
34605
35953
|
const prefix = PathResolver2.getPathPrefix(global3);
|
|
34606
35954
|
if (prefix) {
|
|
34607
|
-
return
|
|
35955
|
+
return join36(baseDir, prefix, "skills");
|
|
34608
35956
|
}
|
|
34609
|
-
return
|
|
35957
|
+
return join36(baseDir, "skills");
|
|
34610
35958
|
}
|
|
34611
35959
|
static buildComponentPath(baseDir, component, global3) {
|
|
34612
35960
|
if (!PathResolver2.isPathSafe(component)) {
|
|
@@ -34614,9 +35962,9 @@ class PathResolver2 {
|
|
|
34614
35962
|
}
|
|
34615
35963
|
const prefix = PathResolver2.getPathPrefix(global3);
|
|
34616
35964
|
if (prefix) {
|
|
34617
|
-
return
|
|
35965
|
+
return join36(baseDir, prefix, component);
|
|
34618
35966
|
}
|
|
34619
|
-
return
|
|
35967
|
+
return join36(baseDir, component);
|
|
34620
35968
|
}
|
|
34621
35969
|
}
|
|
34622
35970
|
|
|
@@ -34648,9 +35996,9 @@ async function displayVersion() {
|
|
|
34648
35996
|
let localKitVersion = null;
|
|
34649
35997
|
let isGlobalOnlyKit = false;
|
|
34650
35998
|
const globalKitDir = PathResolver2.getGlobalKitDir();
|
|
34651
|
-
const globalMetadataPath =
|
|
35999
|
+
const globalMetadataPath = join37(globalKitDir, "metadata.json");
|
|
34652
36000
|
const prefix = PathResolver2.getPathPrefix(false);
|
|
34653
|
-
const localMetadataPath = prefix ?
|
|
36001
|
+
const localMetadataPath = prefix ? join37(process.cwd(), prefix, "metadata.json") : join37(process.cwd(), "metadata.json");
|
|
34654
36002
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
34655
36003
|
if (!isLocalSameAsGlobal && existsSync9(localMetadataPath)) {
|
|
34656
36004
|
try {
|
|
@@ -34754,7 +36102,7 @@ cli.command("versions", "List available versions of ClaudeKit repositories").opt
|
|
|
34754
36102
|
cli.command("doctor", "Comprehensive health check for ClaudeKit").option("--report", "Generate shareable diagnostic report").option("--fix", "Auto-fix all fixable issues").option("--check-only", "CI mode: no prompts, exit 1 on failures").option("--json", "Output JSON format").option("--full", "Include extended priority checks (slower)").action(async (options) => {
|
|
34755
36103
|
await doctorCommand(options);
|
|
34756
36104
|
});
|
|
34757
|
-
cli.command("uninstall", "Remove ClaudeKit installations").option("-y, --yes", "Skip confirmation prompt").option("-l, --local", "Uninstall only local installation (current project)").option("-g, --global", "Uninstall only global installation (~/.claude/)").option("-A, --all", "Uninstall from both local and global locations").option("--dry-run", "Preview what would be removed without deleting").option("--force-overwrite", "Delete even user-modified files (requires confirmation)").action(async (options) => {
|
|
36105
|
+
cli.command("uninstall", "Remove ClaudeKit installations").option("-y, --yes", "Skip confirmation prompt").option("-l, --local", "Uninstall only local installation (current project)").option("-g, --global", "Uninstall only global installation (~/.claude/)").option("-A, --all", "Uninstall from both local and global locations").option("-k, --kit <type>", "Uninstall specific kit only (engineer, marketing)").option("--dry-run", "Preview what would be removed without deleting").option("--force-overwrite", "Delete even user-modified files (requires confirmation)").action(async (options) => {
|
|
34758
36106
|
await uninstallCommand(options);
|
|
34759
36107
|
});
|
|
34760
36108
|
cli.option("-V, --version", "Display version number");
|