claudekit-cli 3.41.4-dev.48 → 3.41.4-dev.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/cli-manifest.json +35 -8
- package/dist/index.js +796 -89
- package/dist/ui/assets/index-CRtJwrzd.css +1 -0
- package/dist/ui/assets/index-DyvVqUTe.js +311 -0
- package/dist/ui/index.html +2 -2
- package/package.json +4 -1
- package/dist/ui/assets/index-CKG4dpEV.js +0 -311
- package/dist/ui/assets/index-D3aRuZaq.css +0 -1
package/dist/index.js
CHANGED
|
@@ -12416,6 +12416,50 @@ function normalizeChecksum(checksum) {
|
|
|
12416
12416
|
function isUnknownChecksum(checksum) {
|
|
12417
12417
|
return normalizeChecksum(checksum) === UNKNOWN_CHECKSUM;
|
|
12418
12418
|
}
|
|
12419
|
+
function getReasonCopy(code, _ctx) {
|
|
12420
|
+
switch (code) {
|
|
12421
|
+
case "new-item":
|
|
12422
|
+
return "New — not previously installed";
|
|
12423
|
+
case "new-provider-for-item":
|
|
12424
|
+
return "New provider for existing item";
|
|
12425
|
+
case "target-deleted-source-changed":
|
|
12426
|
+
return "You deleted this, CK has updates — reinstalling";
|
|
12427
|
+
case "target-dir-empty-reinstall":
|
|
12428
|
+
return "Provider directory is empty — reinstalling";
|
|
12429
|
+
case "force-reinstall":
|
|
12430
|
+
return "Force reinstall (target was deleted)";
|
|
12431
|
+
case "force-overwrite":
|
|
12432
|
+
return "Force overwrite (you edited this, --force active)";
|
|
12433
|
+
case "registry-upgrade-reinstall":
|
|
12434
|
+
return "Target deleted — reinstalling after registry upgrade";
|
|
12435
|
+
case "source-changed":
|
|
12436
|
+
return "CK updated, you didn't edit — safe to overwrite";
|
|
12437
|
+
case "registry-upgrade-heal":
|
|
12438
|
+
return "Healing stale target after registry upgrade";
|
|
12439
|
+
case "no-changes":
|
|
12440
|
+
return "Already up to date";
|
|
12441
|
+
case "user-edits-preserved":
|
|
12442
|
+
return "You edited this, CK unchanged — keeping your edits";
|
|
12443
|
+
case "user-deleted-respected":
|
|
12444
|
+
return "You deleted this, CK unchanged — respecting your choice";
|
|
12445
|
+
case "target-up-to-date-backfill":
|
|
12446
|
+
return "Already up to date — registry checksums will be backfilled";
|
|
12447
|
+
case "provider-checksum-unavailable":
|
|
12448
|
+
return "Provider checksum unavailable — cannot verify safely";
|
|
12449
|
+
case "target-state-unknown":
|
|
12450
|
+
return "Target state unavailable, CK unchanged — preserving target";
|
|
12451
|
+
case "source-removed-orphan":
|
|
12452
|
+
return "No longer shipped by CK — will be removed";
|
|
12453
|
+
case "renamed-cleanup":
|
|
12454
|
+
return "Renamed — cleaning up old path";
|
|
12455
|
+
case "path-migrated-cleanup":
|
|
12456
|
+
return "Path migrated — cleaning up old location";
|
|
12457
|
+
case "both-changed":
|
|
12458
|
+
return "Both you and CK changed this — pick one";
|
|
12459
|
+
case "target-state-unknown-source-changed":
|
|
12460
|
+
return "Target state unavailable while CK changed — manual review required";
|
|
12461
|
+
}
|
|
12462
|
+
}
|
|
12419
12463
|
var UNKNOWN_CHECKSUM = "unknown";
|
|
12420
12464
|
|
|
12421
12465
|
// src/commands/portable/portable-registry.ts
|
|
@@ -54357,7 +54401,7 @@ var init_reconcile_registry_backfill = __esm(() => {
|
|
|
54357
54401
|
});
|
|
54358
54402
|
|
|
54359
54403
|
// src/commands/portable/reconcile-state-builders.ts
|
|
54360
|
-
import { existsSync as existsSync27 } from "node:fs";
|
|
54404
|
+
import { existsSync as existsSync27, readdirSync as readdirSync3, statSync as statSync5 } from "node:fs";
|
|
54361
54405
|
import { readFile as readFile23 } from "node:fs/promises";
|
|
54362
54406
|
function getProviderPathKeyForPortableType2(type) {
|
|
54363
54407
|
switch (type) {
|
|
@@ -54453,6 +54497,95 @@ function buildSourceItemState(item, type, selectedProviders, options2) {
|
|
|
54453
54497
|
targetChecksums
|
|
54454
54498
|
};
|
|
54455
54499
|
}
|
|
54500
|
+
function buildTypeDirectoryStates(providerConfigs, types4) {
|
|
54501
|
+
const results = [];
|
|
54502
|
+
for (const { provider, global: isGlobal } of providerConfigs) {
|
|
54503
|
+
const providerConfig = providers[provider];
|
|
54504
|
+
if (!providerConfig)
|
|
54505
|
+
continue;
|
|
54506
|
+
for (const type of types4) {
|
|
54507
|
+
const pathKey = portableTypeToProviderPathKey(type);
|
|
54508
|
+
const pathConfig = providerConfig[pathKey];
|
|
54509
|
+
if (!pathConfig)
|
|
54510
|
+
continue;
|
|
54511
|
+
if (pathConfig.writeStrategy === "merge-single" || pathConfig.writeStrategy === "single-file") {
|
|
54512
|
+
continue;
|
|
54513
|
+
}
|
|
54514
|
+
const dirPath = isGlobal ? pathConfig.globalPath : pathConfig.projectPath;
|
|
54515
|
+
if (!dirPath)
|
|
54516
|
+
continue;
|
|
54517
|
+
const exists = existsSync27(dirPath);
|
|
54518
|
+
if (!exists) {
|
|
54519
|
+
results.push({
|
|
54520
|
+
provider,
|
|
54521
|
+
type,
|
|
54522
|
+
global: isGlobal,
|
|
54523
|
+
path: dirPath,
|
|
54524
|
+
exists: false,
|
|
54525
|
+
isEmpty: true,
|
|
54526
|
+
fileCount: 0
|
|
54527
|
+
});
|
|
54528
|
+
continue;
|
|
54529
|
+
}
|
|
54530
|
+
let stat7 = null;
|
|
54531
|
+
try {
|
|
54532
|
+
stat7 = statSync5(dirPath);
|
|
54533
|
+
} catch {
|
|
54534
|
+
results.push({
|
|
54535
|
+
provider,
|
|
54536
|
+
type,
|
|
54537
|
+
global: isGlobal,
|
|
54538
|
+
path: dirPath,
|
|
54539
|
+
exists: false,
|
|
54540
|
+
isEmpty: true,
|
|
54541
|
+
fileCount: 0
|
|
54542
|
+
});
|
|
54543
|
+
continue;
|
|
54544
|
+
}
|
|
54545
|
+
if (!stat7.isDirectory()) {
|
|
54546
|
+
results.push({
|
|
54547
|
+
provider,
|
|
54548
|
+
type,
|
|
54549
|
+
global: isGlobal,
|
|
54550
|
+
path: dirPath,
|
|
54551
|
+
exists: true,
|
|
54552
|
+
isEmpty: false,
|
|
54553
|
+
fileCount: 1
|
|
54554
|
+
});
|
|
54555
|
+
continue;
|
|
54556
|
+
}
|
|
54557
|
+
const ext = pathConfig.fileExtension ?? "";
|
|
54558
|
+
let entries = [];
|
|
54559
|
+
try {
|
|
54560
|
+
entries = readdirSync3(dirPath);
|
|
54561
|
+
} catch {
|
|
54562
|
+
results.push({
|
|
54563
|
+
provider,
|
|
54564
|
+
type,
|
|
54565
|
+
global: isGlobal,
|
|
54566
|
+
path: dirPath,
|
|
54567
|
+
exists: true,
|
|
54568
|
+
isEmpty: true,
|
|
54569
|
+
fileCount: 0
|
|
54570
|
+
});
|
|
54571
|
+
continue;
|
|
54572
|
+
}
|
|
54573
|
+
const managedFiles = ext === "" ? entries.filter((f3) => {
|
|
54574
|
+
return f3.endsWith(".json") || f3.endsWith(".sh") || f3.endsWith(".js");
|
|
54575
|
+
}) : entries.filter((f3) => f3.endsWith(ext));
|
|
54576
|
+
results.push({
|
|
54577
|
+
provider,
|
|
54578
|
+
type,
|
|
54579
|
+
global: isGlobal,
|
|
54580
|
+
path: dirPath,
|
|
54581
|
+
exists: true,
|
|
54582
|
+
isEmpty: managedFiles.length === 0,
|
|
54583
|
+
fileCount: managedFiles.length
|
|
54584
|
+
});
|
|
54585
|
+
}
|
|
54586
|
+
}
|
|
54587
|
+
return results;
|
|
54588
|
+
}
|
|
54456
54589
|
async function buildTargetStates(entries, options2) {
|
|
54457
54590
|
const targetStates = new Map;
|
|
54458
54591
|
const entriesByPath = new Map;
|
|
@@ -54481,11 +54614,13 @@ async function buildTargetStates(entries, options2) {
|
|
|
54481
54614
|
}
|
|
54482
54615
|
return targetStates;
|
|
54483
54616
|
}
|
|
54617
|
+
var portableTypeToProviderPathKey;
|
|
54484
54618
|
var init_reconcile_state_builders = __esm(() => {
|
|
54485
54619
|
init_checksum_utils();
|
|
54486
54620
|
init_converters();
|
|
54487
54621
|
init_merge_single_sections();
|
|
54488
54622
|
init_provider_registry();
|
|
54623
|
+
portableTypeToProviderPathKey = getProviderPathKeyForPortableType2;
|
|
54489
54624
|
});
|
|
54490
54625
|
|
|
54491
54626
|
// src/commands/portable/reconciler.ts
|
|
@@ -54538,6 +54673,9 @@ function makeItemTypeKey(item, type) {
|
|
|
54538
54673
|
function makeRegistryIdentityKey(entry) {
|
|
54539
54674
|
return JSON.stringify([entry.item, entry.type, entry.provider, entry.global]);
|
|
54540
54675
|
}
|
|
54676
|
+
function makeDirStateKey(provider, type, global3) {
|
|
54677
|
+
return JSON.stringify([provider, type, global3]);
|
|
54678
|
+
}
|
|
54541
54679
|
function dedupeProviderConfigs(providerConfigs) {
|
|
54542
54680
|
const seen = new Set;
|
|
54543
54681
|
const unique = [];
|
|
@@ -54564,6 +54702,14 @@ function buildTargetStateIndex(targetStates) {
|
|
|
54564
54702
|
}
|
|
54565
54703
|
return index;
|
|
54566
54704
|
}
|
|
54705
|
+
function buildDirStateIndex(dirStates) {
|
|
54706
|
+
const index = new Map;
|
|
54707
|
+
for (const ds of dirStates) {
|
|
54708
|
+
const key = makeDirStateKey(ds.provider, ds.type, ds.global);
|
|
54709
|
+
index.set(key, ds);
|
|
54710
|
+
}
|
|
54711
|
+
return index;
|
|
54712
|
+
}
|
|
54567
54713
|
function lookupTargetState(targetStateIndex, pathValue) {
|
|
54568
54714
|
return targetStateIndex.get(normalizePortablePath(pathValue));
|
|
54569
54715
|
}
|
|
@@ -54647,6 +54793,66 @@ function suppressOverlappingActions(actions) {
|
|
|
54647
54793
|
}
|
|
54648
54794
|
return filtered;
|
|
54649
54795
|
}
|
|
54796
|
+
function applyEmptyDirOverride(actions, dirStates, respectDeletions) {
|
|
54797
|
+
if (dirStates.length === 0) {
|
|
54798
|
+
return { actions, banners: [] };
|
|
54799
|
+
}
|
|
54800
|
+
const dirIndex = buildDirStateIndex(dirStates);
|
|
54801
|
+
const banners = [];
|
|
54802
|
+
const flippedGroups = new Map;
|
|
54803
|
+
for (const action of actions) {
|
|
54804
|
+
if (action.action !== "skip" || action.reasonCode !== "user-deleted-respected") {
|
|
54805
|
+
continue;
|
|
54806
|
+
}
|
|
54807
|
+
const key = makeDirStateKey(action.provider, action.type, action.global);
|
|
54808
|
+
const dirState = dirIndex.get(key);
|
|
54809
|
+
if (!dirState?.isEmpty)
|
|
54810
|
+
continue;
|
|
54811
|
+
if (respectDeletions) {
|
|
54812
|
+
const existing2 = flippedGroups.get(key);
|
|
54813
|
+
if (existing2) {
|
|
54814
|
+
existing2.count++;
|
|
54815
|
+
} else {
|
|
54816
|
+
flippedGroups.set(key, { dirState, count: 1 });
|
|
54817
|
+
}
|
|
54818
|
+
continue;
|
|
54819
|
+
}
|
|
54820
|
+
action.action = "install";
|
|
54821
|
+
action.reasonCode = "target-dir-empty-reinstall";
|
|
54822
|
+
action.reasonCopy = getReasonCopy("target-dir-empty-reinstall");
|
|
54823
|
+
action.reason = action.reasonCopy;
|
|
54824
|
+
const existing = flippedGroups.get(key);
|
|
54825
|
+
if (existing) {
|
|
54826
|
+
existing.count++;
|
|
54827
|
+
} else {
|
|
54828
|
+
flippedGroups.set(key, { dirState, count: 1 });
|
|
54829
|
+
}
|
|
54830
|
+
}
|
|
54831
|
+
for (const [, { dirState, count }] of flippedGroups) {
|
|
54832
|
+
if (respectDeletions) {
|
|
54833
|
+
banners.push({
|
|
54834
|
+
kind: "empty-dir-respected",
|
|
54835
|
+
provider: dirState.provider,
|
|
54836
|
+
type: dirState.type,
|
|
54837
|
+
global: dirState.global,
|
|
54838
|
+
path: dirState.path,
|
|
54839
|
+
itemCount: count,
|
|
54840
|
+
message: `Detected empty ${dirState.path} — respecting your deletions (${count} items skipped).`
|
|
54841
|
+
});
|
|
54842
|
+
} else {
|
|
54843
|
+
banners.push({
|
|
54844
|
+
kind: "empty-dir",
|
|
54845
|
+
provider: dirState.provider,
|
|
54846
|
+
type: dirState.type,
|
|
54847
|
+
global: dirState.global,
|
|
54848
|
+
path: dirState.path,
|
|
54849
|
+
itemCount: count,
|
|
54850
|
+
message: `Detected empty ${dirState.path} — ${count} item${count === 1 ? "" : "s"} will be reinstalled. Uncheck any to skip.`
|
|
54851
|
+
});
|
|
54852
|
+
}
|
|
54853
|
+
}
|
|
54854
|
+
return { actions, banners };
|
|
54855
|
+
}
|
|
54650
54856
|
function reconcile(input) {
|
|
54651
54857
|
const actions = [];
|
|
54652
54858
|
const targetStateIndex = buildTargetStateIndex(input.targetStates);
|
|
@@ -54676,7 +54882,10 @@ function reconcile(input) {
|
|
|
54676
54882
|
const orphanActions = detectOrphans(input, renamedFromKeys);
|
|
54677
54883
|
actions.push(...orphanActions);
|
|
54678
54884
|
const normalizedActions = suppressOverlappingActions(dedupeActions(actions));
|
|
54679
|
-
|
|
54885
|
+
const dirStates = input.typeDirectoryStates ?? [];
|
|
54886
|
+
const respectDeletions = input.respectDeletions ?? false;
|
|
54887
|
+
const { actions: finalActions, banners } = applyEmptyDirOverride(normalizedActions, dirStates, respectDeletions);
|
|
54888
|
+
return buildPlan(finalActions, banners);
|
|
54680
54889
|
}
|
|
54681
54890
|
function determineAction(source, providerConfig, input, targetStateIndex, deletedIdentityKeys) {
|
|
54682
54891
|
let registryEntry = findRegistryEntry(source, providerConfig, input.registry);
|
|
@@ -54689,12 +54898,14 @@ function determineAction(source, providerConfig, input, targetStateIndex, delete
|
|
|
54689
54898
|
if (registryEntry && deletedIdentityKeys.has(identityKey)) {
|
|
54690
54899
|
registryEntry = null;
|
|
54691
54900
|
}
|
|
54901
|
+
const isDirectoryItem = source.type === "skill";
|
|
54692
54902
|
const common = {
|
|
54693
54903
|
item: source.item,
|
|
54694
54904
|
type: source.type,
|
|
54695
54905
|
provider: providerConfig.provider,
|
|
54696
54906
|
global: providerConfig.global,
|
|
54697
|
-
targetPath: ""
|
|
54907
|
+
targetPath: "",
|
|
54908
|
+
isDirectoryItem: isDirectoryItem || undefined
|
|
54698
54909
|
};
|
|
54699
54910
|
const convertedChecksumRaw = source.convertedChecksums[providerConfig.provider];
|
|
54700
54911
|
const convertedChecksum = normalizeChecksum(convertedChecksumRaw);
|
|
@@ -54702,30 +54913,39 @@ function determineAction(source, providerConfig, input, targetStateIndex, delete
|
|
|
54702
54913
|
if (!convertedChecksumRaw || isUnknownChecksum(convertedChecksumRaw)) {
|
|
54703
54914
|
if (registryEntry) {
|
|
54704
54915
|
common.targetPath = registryEntry.path;
|
|
54916
|
+
const code3 = "provider-checksum-unavailable";
|
|
54705
54917
|
return {
|
|
54706
54918
|
...common,
|
|
54707
54919
|
action: "skip",
|
|
54708
54920
|
reason: "Provider checksum unavailable — cannot verify safely",
|
|
54921
|
+
reasonCode: code3,
|
|
54922
|
+
reasonCopy: getReasonCopy(code3),
|
|
54709
54923
|
sourceChecksum: UNKNOWN_CHECKSUM,
|
|
54710
54924
|
registeredSourceChecksum: normalizeChecksum(registryEntry.sourceChecksum),
|
|
54711
54925
|
registeredTargetChecksum: normalizeChecksum(registryEntry.targetChecksum)
|
|
54712
54926
|
};
|
|
54713
54927
|
}
|
|
54714
54928
|
const itemExistsElsewhere = input.registry.installations.some((i) => i.item === source.item && i.type === source.type);
|
|
54929
|
+
const code2 = itemExistsElsewhere ? "new-provider-for-item" : "new-item";
|
|
54715
54930
|
return {
|
|
54716
54931
|
...common,
|
|
54717
54932
|
action: "install",
|
|
54718
54933
|
reason: itemExistsElsewhere ? "New provider for existing item" : "New item, not previously installed",
|
|
54934
|
+
reasonCode: code2,
|
|
54935
|
+
reasonCopy: getReasonCopy(code2),
|
|
54719
54936
|
sourceChecksum: UNKNOWN_CHECKSUM
|
|
54720
54937
|
};
|
|
54721
54938
|
}
|
|
54722
54939
|
if (!registryEntry) {
|
|
54723
54940
|
const itemExistsElsewhere = input.registry.installations.some((i) => i.item === source.item && i.type === source.type);
|
|
54941
|
+
const code2 = itemExistsElsewhere ? "new-provider-for-item" : "new-item";
|
|
54724
54942
|
const reason = itemExistsElsewhere ? "New provider for existing item" : "New item, not previously installed";
|
|
54725
54943
|
return {
|
|
54726
54944
|
...common,
|
|
54727
54945
|
action: "install",
|
|
54728
54946
|
reason,
|
|
54947
|
+
reasonCode: code2,
|
|
54948
|
+
reasonCopy: getReasonCopy(code2),
|
|
54729
54949
|
sourceChecksum: convertedChecksum
|
|
54730
54950
|
};
|
|
54731
54951
|
}
|
|
@@ -54737,36 +54957,48 @@ function determineAction(source, providerConfig, input, targetStateIndex, delete
|
|
|
54737
54957
|
const targetMatchesExpectedOutput = targetState?.exists === true && !isUnknownChecksum(expectedTargetChecksum) && currentTargetChecksum === expectedTargetChecksum;
|
|
54738
54958
|
if (isUnknownChecksum(registeredSourceChecksum)) {
|
|
54739
54959
|
if (targetMatchesExpectedOutput) {
|
|
54960
|
+
const code3 = "target-up-to-date-backfill";
|
|
54740
54961
|
return {
|
|
54741
54962
|
...common,
|
|
54742
54963
|
action: "skip",
|
|
54743
54964
|
reason: "Target up-to-date after registry upgrade — checksums will be backfilled",
|
|
54965
|
+
reasonCode: code3,
|
|
54966
|
+
reasonCopy: getReasonCopy(code3),
|
|
54744
54967
|
sourceChecksum: convertedChecksum,
|
|
54745
54968
|
currentTargetChecksum,
|
|
54746
54969
|
backfillRegistry: true
|
|
54747
54970
|
};
|
|
54748
54971
|
}
|
|
54749
54972
|
if (!targetState || !targetState.exists) {
|
|
54973
|
+
const code3 = "registry-upgrade-reinstall";
|
|
54750
54974
|
return {
|
|
54751
54975
|
...common,
|
|
54752
54976
|
action: "install",
|
|
54753
54977
|
reason: "Target deleted — reinstalling after registry upgrade",
|
|
54978
|
+
reasonCode: code3,
|
|
54979
|
+
reasonCopy: getReasonCopy(code3),
|
|
54754
54980
|
sourceChecksum: convertedChecksum
|
|
54755
54981
|
};
|
|
54756
54982
|
}
|
|
54983
|
+
const code2 = "registry-upgrade-heal";
|
|
54757
54984
|
return {
|
|
54758
54985
|
...common,
|
|
54759
54986
|
action: "update",
|
|
54760
54987
|
reason: "Healing stale target after registry upgrade",
|
|
54988
|
+
reasonCode: code2,
|
|
54989
|
+
reasonCopy: getReasonCopy(code2),
|
|
54761
54990
|
sourceChecksum: convertedChecksum,
|
|
54762
54991
|
currentTargetChecksum
|
|
54763
54992
|
};
|
|
54764
54993
|
}
|
|
54765
54994
|
if (targetMatchesExpectedOutput && (convertedChecksum !== registeredSourceChecksum || currentTargetChecksum !== registeredTargetChecksum)) {
|
|
54995
|
+
const code2 = "target-up-to-date-backfill";
|
|
54766
54996
|
return {
|
|
54767
54997
|
...common,
|
|
54768
54998
|
action: "skip",
|
|
54769
54999
|
reason: "Target up-to-date — registry checksums will be backfilled",
|
|
55000
|
+
reasonCode: code2,
|
|
55001
|
+
reasonCopy: getReasonCopy(code2),
|
|
54770
55002
|
sourceChecksum: convertedChecksum,
|
|
54771
55003
|
registeredSourceChecksum,
|
|
54772
55004
|
currentTargetChecksum,
|
|
@@ -54778,19 +55010,49 @@ function determineAction(source, providerConfig, input, targetStateIndex, delete
|
|
|
54778
55010
|
const targetChangeState = getTargetChangeState(targetState, registryEntry, registeredTargetChecksum);
|
|
54779
55011
|
if (targetChangeState === "deleted") {
|
|
54780
55012
|
const forceReinstall = input.force && !sourceChanged;
|
|
55013
|
+
if (sourceChanged) {
|
|
55014
|
+
const code3 = "target-deleted-source-changed";
|
|
55015
|
+
return {
|
|
55016
|
+
...common,
|
|
55017
|
+
action: "install",
|
|
55018
|
+
reason: "Target was deleted, CK has updates — reinstalling",
|
|
55019
|
+
reasonCode: code3,
|
|
55020
|
+
reasonCopy: getReasonCopy(code3),
|
|
55021
|
+
sourceChecksum: convertedChecksum,
|
|
55022
|
+
registeredSourceChecksum
|
|
55023
|
+
};
|
|
55024
|
+
}
|
|
55025
|
+
if (forceReinstall) {
|
|
55026
|
+
const code3 = "force-reinstall";
|
|
55027
|
+
return {
|
|
55028
|
+
...common,
|
|
55029
|
+
action: "install",
|
|
55030
|
+
reason: "Force reinstall (target was deleted)",
|
|
55031
|
+
reasonCode: code3,
|
|
55032
|
+
reasonCopy: getReasonCopy(code3),
|
|
55033
|
+
sourceChecksum: convertedChecksum,
|
|
55034
|
+
registeredSourceChecksum
|
|
55035
|
+
};
|
|
55036
|
+
}
|
|
55037
|
+
const code2 = "user-deleted-respected";
|
|
54781
55038
|
return {
|
|
54782
55039
|
...common,
|
|
54783
|
-
action:
|
|
54784
|
-
reason:
|
|
55040
|
+
action: "skip",
|
|
55041
|
+
reason: "Target was deleted by user, CK unchanged — respecting deletion",
|
|
55042
|
+
reasonCode: code2,
|
|
55043
|
+
reasonCopy: getReasonCopy(code2),
|
|
54785
55044
|
sourceChecksum: convertedChecksum,
|
|
54786
55045
|
registeredSourceChecksum
|
|
54787
55046
|
};
|
|
54788
55047
|
}
|
|
54789
55048
|
if (targetChangeState === "unknown") {
|
|
55049
|
+
const code2 = sourceChanged ? "target-state-unknown-source-changed" : "target-state-unknown";
|
|
54790
55050
|
return {
|
|
54791
55051
|
...common,
|
|
54792
55052
|
action: sourceChanged ? "conflict" : "skip",
|
|
54793
55053
|
reason: sourceChanged ? "Target state unavailable while CK changed — manual review required" : "Target state unavailable, CK unchanged — preserving target",
|
|
55054
|
+
reasonCode: code2,
|
|
55055
|
+
reasonCopy: getReasonCopy(code2),
|
|
54794
55056
|
sourceChecksum: convertedChecksum,
|
|
54795
55057
|
registeredSourceChecksum,
|
|
54796
55058
|
currentTargetChecksum,
|
|
@@ -54799,19 +55061,38 @@ function determineAction(source, providerConfig, input, targetStateIndex, delete
|
|
|
54799
55061
|
}
|
|
54800
55062
|
const targetChanged = targetChangeState === "changed";
|
|
54801
55063
|
if (!sourceChanged && !targetChanged) {
|
|
55064
|
+
const code2 = "no-changes";
|
|
54802
55065
|
return {
|
|
54803
55066
|
...common,
|
|
54804
55067
|
action: "skip",
|
|
54805
55068
|
reason: "No changes",
|
|
55069
|
+
reasonCode: code2,
|
|
55070
|
+
reasonCopy: getReasonCopy(code2),
|
|
54806
55071
|
sourceChecksum: convertedChecksum,
|
|
54807
55072
|
currentTargetChecksum
|
|
54808
55073
|
};
|
|
54809
55074
|
}
|
|
54810
55075
|
if (!sourceChanged && targetChanged) {
|
|
55076
|
+
if (input.force) {
|
|
55077
|
+
return {
|
|
55078
|
+
...common,
|
|
55079
|
+
action: "install",
|
|
55080
|
+
reason: "Force overwrite (user edits)",
|
|
55081
|
+
reasonCode: "force-overwrite",
|
|
55082
|
+
reasonCopy: getReasonCopy("force-overwrite"),
|
|
55083
|
+
sourceChecksum: convertedChecksum,
|
|
55084
|
+
registeredSourceChecksum,
|
|
55085
|
+
currentTargetChecksum,
|
|
55086
|
+
registeredTargetChecksum
|
|
55087
|
+
};
|
|
55088
|
+
}
|
|
55089
|
+
const code2 = "user-edits-preserved";
|
|
54811
55090
|
return {
|
|
54812
55091
|
...common,
|
|
54813
|
-
action:
|
|
54814
|
-
reason:
|
|
55092
|
+
action: "skip",
|
|
55093
|
+
reason: "User edited, CK unchanged — preserving edits",
|
|
55094
|
+
reasonCode: code2,
|
|
55095
|
+
reasonCopy: getReasonCopy(code2),
|
|
54815
55096
|
sourceChecksum: convertedChecksum,
|
|
54816
55097
|
registeredSourceChecksum,
|
|
54817
55098
|
currentTargetChecksum,
|
|
@@ -54819,20 +55100,26 @@ function determineAction(source, providerConfig, input, targetStateIndex, delete
|
|
|
54819
55100
|
};
|
|
54820
55101
|
}
|
|
54821
55102
|
if (sourceChanged && !targetChanged) {
|
|
55103
|
+
const code2 = "source-changed";
|
|
54822
55104
|
return {
|
|
54823
55105
|
...common,
|
|
54824
55106
|
action: "update",
|
|
54825
55107
|
reason: "CK updated, no user edits — safe overwrite",
|
|
55108
|
+
reasonCode: code2,
|
|
55109
|
+
reasonCopy: getReasonCopy(code2),
|
|
54826
55110
|
sourceChecksum: convertedChecksum,
|
|
54827
55111
|
registeredSourceChecksum,
|
|
54828
55112
|
currentTargetChecksum,
|
|
54829
55113
|
registeredTargetChecksum
|
|
54830
55114
|
};
|
|
54831
55115
|
}
|
|
55116
|
+
const code = "both-changed";
|
|
54832
55117
|
return {
|
|
54833
55118
|
...common,
|
|
54834
55119
|
action: "conflict",
|
|
54835
55120
|
reason: "Both CK and user modified this item",
|
|
55121
|
+
reasonCode: code,
|
|
55122
|
+
reasonCopy: getReasonCopy(code),
|
|
54836
55123
|
sourceChecksum: convertedChecksum,
|
|
54837
55124
|
registeredSourceChecksum,
|
|
54838
55125
|
currentTargetChecksum,
|
|
@@ -54868,6 +55155,7 @@ function detectOrphans(input, renamedFromKeys) {
|
|
|
54868
55155
|
if (entry.type === "config" && hasConfigSource)
|
|
54869
55156
|
continue;
|
|
54870
55157
|
if (!sourceItemKeys.has(sourceItemKey)) {
|
|
55158
|
+
const code = "source-removed-orphan";
|
|
54871
55159
|
actions.push({
|
|
54872
55160
|
action: "delete",
|
|
54873
55161
|
item: entry.item,
|
|
@@ -54875,7 +55163,9 @@ function detectOrphans(input, renamedFromKeys) {
|
|
|
54875
55163
|
provider: entry.provider,
|
|
54876
55164
|
global: entry.global,
|
|
54877
55165
|
targetPath: entry.path,
|
|
54878
|
-
reason: "Item no longer in CK source — orphaned"
|
|
55166
|
+
reason: "Item no longer in CK source — orphaned",
|
|
55167
|
+
reasonCode: code,
|
|
55168
|
+
reasonCopy: getReasonCopy(code)
|
|
54879
55169
|
});
|
|
54880
55170
|
}
|
|
54881
55171
|
}
|
|
@@ -54894,6 +55184,7 @@ function detectRenames(input) {
|
|
|
54894
55184
|
const normalizedFrom = normalizePortablePath(rename8.from);
|
|
54895
55185
|
const oldEntries = input.registry.installations.filter((e2) => normalizePortablePath(e2.sourcePath) === normalizedFrom);
|
|
54896
55186
|
for (const oldEntry of oldEntries) {
|
|
55187
|
+
const code = "renamed-cleanup";
|
|
54897
55188
|
actions.push({
|
|
54898
55189
|
deleteAction: {
|
|
54899
55190
|
action: "delete",
|
|
@@ -54903,6 +55194,8 @@ function detectRenames(input) {
|
|
|
54903
55194
|
global: oldEntry.global,
|
|
54904
55195
|
targetPath: oldEntry.path,
|
|
54905
55196
|
reason: `Renamed: ${rename8.from} -> ${rename8.to}`,
|
|
55197
|
+
reasonCode: code,
|
|
55198
|
+
reasonCopy: getReasonCopy(code),
|
|
54906
55199
|
previousItem: oldEntry.item
|
|
54907
55200
|
},
|
|
54908
55201
|
newItem: oldEntry.item
|
|
@@ -54919,6 +55212,7 @@ function detectPathMigrations(input) {
|
|
|
54919
55212
|
for (const migration of applicable) {
|
|
54920
55213
|
const affectedEntries = input.registry.installations.filter((e2) => e2.provider === migration.provider && e2.type === migration.type && pathContainsSegments(e2.path, migration.from));
|
|
54921
55214
|
for (const entry of affectedEntries) {
|
|
55215
|
+
const code = "path-migrated-cleanup";
|
|
54922
55216
|
actions.push({
|
|
54923
55217
|
deleteAction: {
|
|
54924
55218
|
action: "delete",
|
|
@@ -54928,6 +55222,8 @@ function detectPathMigrations(input) {
|
|
|
54928
55222
|
global: entry.global,
|
|
54929
55223
|
targetPath: entry.path,
|
|
54930
55224
|
reason: `Provider path migrated: ${migration.from} -> ${migration.to}`,
|
|
55225
|
+
reasonCode: code,
|
|
55226
|
+
reasonCopy: getReasonCopy(code),
|
|
54931
55227
|
previousPath: entry.path
|
|
54932
55228
|
}
|
|
54933
55229
|
});
|
|
@@ -54938,7 +55234,7 @@ function detectPathMigrations(input) {
|
|
|
54938
55234
|
function detectSectionRenames(_input) {
|
|
54939
55235
|
return [];
|
|
54940
55236
|
}
|
|
54941
|
-
function buildPlan(actions) {
|
|
55237
|
+
function buildPlan(actions, banners) {
|
|
54942
55238
|
const summary = { install: 0, update: 0, skip: 0, conflict: 0, delete: 0 };
|
|
54943
55239
|
for (const action of actions) {
|
|
54944
55240
|
summary[action.action]++;
|
|
@@ -54946,7 +55242,8 @@ function buildPlan(actions) {
|
|
|
54946
55242
|
return {
|
|
54947
55243
|
actions,
|
|
54948
55244
|
summary,
|
|
54949
|
-
hasConflicts: summary.conflict > 0
|
|
55245
|
+
hasConflicts: summary.conflict > 0,
|
|
55246
|
+
banners
|
|
54950
55247
|
};
|
|
54951
55248
|
}
|
|
54952
55249
|
var init_reconciler = __esm(() => {
|
|
@@ -55969,6 +56266,28 @@ function registerMigrationRoutes(app) {
|
|
|
55969
56266
|
return;
|
|
55970
56267
|
}
|
|
55971
56268
|
const configSource = sourceParsed.value;
|
|
56269
|
+
const reinstallEmptyDirsParsed = parseBooleanLike(req.query.reinstallEmptyDirs);
|
|
56270
|
+
if (!reinstallEmptyDirsParsed.ok) {
|
|
56271
|
+
res.status(400).json({ error: `reinstallEmptyDirs ${reinstallEmptyDirsParsed.error}` });
|
|
56272
|
+
return;
|
|
56273
|
+
}
|
|
56274
|
+
const reinstallEmptyDirs = reinstallEmptyDirsParsed.value !== false;
|
|
56275
|
+
const respectDeletionsParsed = parseBooleanLike(req.query.respectDeletions);
|
|
56276
|
+
if (!respectDeletionsParsed.ok) {
|
|
56277
|
+
res.status(400).json({ error: `respectDeletions ${respectDeletionsParsed.error}` });
|
|
56278
|
+
return;
|
|
56279
|
+
}
|
|
56280
|
+
const respectDeletions = respectDeletionsParsed.value === true;
|
|
56281
|
+
const modeRaw = req.query.mode;
|
|
56282
|
+
let reconcileMode = "reconcile";
|
|
56283
|
+
if (modeRaw !== undefined) {
|
|
56284
|
+
const modeStr = String(modeRaw).trim().toLowerCase();
|
|
56285
|
+
if (modeStr !== "reconcile" && modeStr !== "install") {
|
|
56286
|
+
res.status(400).json({ error: "mode must be 'reconcile' or 'install'" });
|
|
56287
|
+
return;
|
|
56288
|
+
}
|
|
56289
|
+
reconcileMode = modeStr;
|
|
56290
|
+
}
|
|
55972
56291
|
const discovered = await discoverMigrationItems(include, configSource);
|
|
55973
56292
|
const sourceItems = [];
|
|
55974
56293
|
for (const agent of discovered.agents) {
|
|
@@ -56054,20 +56373,33 @@ function registerMigrationRoutes(app) {
|
|
|
56054
56373
|
provider,
|
|
56055
56374
|
global: globalParam
|
|
56056
56375
|
}));
|
|
56376
|
+
const enabledTypes = ["agent", "command", "skill", "config", "rules", "hooks"].filter((type) => {
|
|
56377
|
+
const key = type === "agent" ? "agents" : type === "command" ? "commands" : type === "skill" ? "skills" : type === "config" ? "config" : type === "rules" ? "rules" : "hooks";
|
|
56378
|
+
return include[key];
|
|
56379
|
+
});
|
|
56380
|
+
const typeDirectoryStates = reinstallEmptyDirs ? buildTypeDirectoryStates(providerConfigs.map((p) => ({
|
|
56381
|
+
provider: p.provider,
|
|
56382
|
+
global: p.global
|
|
56383
|
+
})), enabledTypes) : undefined;
|
|
56057
56384
|
const input = {
|
|
56058
56385
|
sourceItems,
|
|
56059
56386
|
registry,
|
|
56060
56387
|
targetStates,
|
|
56061
56388
|
manifest,
|
|
56062
|
-
providerConfigs
|
|
56389
|
+
providerConfigs,
|
|
56390
|
+
typeDirectoryStates,
|
|
56391
|
+
respectDeletions
|
|
56063
56392
|
};
|
|
56064
56393
|
const plan = reconcile(input);
|
|
56394
|
+
const hasUnknownChecksum = registry.installations.some((inst) => isUnknownChecksum(inst.sourceChecksum) || isUnknownChecksum(inst.targetChecksum));
|
|
56395
|
+
const suggestedMode = hasUnknownChecksum ? "install" : "reconcile";
|
|
56065
56396
|
const planWithMeta = {
|
|
56066
56397
|
...plan,
|
|
56067
56398
|
meta: {
|
|
56068
56399
|
include,
|
|
56069
56400
|
providers: selectedProviders,
|
|
56070
56401
|
source: configSource,
|
|
56402
|
+
mode: reconcileMode,
|
|
56071
56403
|
items: {
|
|
56072
56404
|
agents: discovered.agents.map((item) => item.name),
|
|
56073
56405
|
commands: discovered.commands.map((item) => item.name),
|
|
@@ -56078,7 +56410,10 @@ function registerMigrationRoutes(app) {
|
|
|
56078
56410
|
}
|
|
56079
56411
|
}
|
|
56080
56412
|
};
|
|
56081
|
-
res.status(200).json({
|
|
56413
|
+
res.status(200).json({
|
|
56414
|
+
plan: planWithMeta,
|
|
56415
|
+
suggestedMode
|
|
56416
|
+
});
|
|
56082
56417
|
} catch (error) {
|
|
56083
56418
|
res.status(500).json({
|
|
56084
56419
|
error: "Failed to compute reconcile plan",
|
|
@@ -56086,6 +56421,123 @@ function registerMigrationRoutes(app) {
|
|
|
56086
56421
|
});
|
|
56087
56422
|
}
|
|
56088
56423
|
});
|
|
56424
|
+
app.get("/api/migrate/install-discovery", async (req, res) => {
|
|
56425
|
+
try {
|
|
56426
|
+
let addCandidates = function(items, type, isDirectoryItem) {
|
|
56427
|
+
for (const item of items) {
|
|
56428
|
+
const sourcePath = item.sourcePath ?? item.path ?? "";
|
|
56429
|
+
for (const provider of selectedProviders) {
|
|
56430
|
+
const registryEntry = registry.installations.find((inst) => inst.item === item.name && inst.type === type && inst.provider === provider && inst.global === globalParam);
|
|
56431
|
+
const alreadyInstalled = registryEntry !== undefined;
|
|
56432
|
+
candidates.push({
|
|
56433
|
+
item: item.name,
|
|
56434
|
+
type,
|
|
56435
|
+
provider,
|
|
56436
|
+
global: globalParam,
|
|
56437
|
+
isDirectoryItem,
|
|
56438
|
+
description: item.description,
|
|
56439
|
+
sourcePath,
|
|
56440
|
+
alreadyInstalled,
|
|
56441
|
+
registryPath: alreadyInstalled ? registryEntry?.path : undefined
|
|
56442
|
+
});
|
|
56443
|
+
}
|
|
56444
|
+
}
|
|
56445
|
+
};
|
|
56446
|
+
const providersParsed = parseProvidersFromQuery(req.query.providers);
|
|
56447
|
+
if (!providersParsed.ok || !providersParsed.value) {
|
|
56448
|
+
res.status(400).json({ error: providersParsed.error || "Invalid providers parameter" });
|
|
56449
|
+
return;
|
|
56450
|
+
}
|
|
56451
|
+
const selectedProviders = providersParsed.value;
|
|
56452
|
+
const includeParsed = parseIncludeOptionsStrict({
|
|
56453
|
+
agents: req.query.agents,
|
|
56454
|
+
commands: req.query.commands,
|
|
56455
|
+
skills: req.query.skills,
|
|
56456
|
+
config: req.query.config,
|
|
56457
|
+
rules: req.query.rules,
|
|
56458
|
+
hooks: req.query.hooks
|
|
56459
|
+
}, "");
|
|
56460
|
+
if (!includeParsed.ok || !includeParsed.value) {
|
|
56461
|
+
res.status(400).json({ error: includeParsed.error || "Invalid include options" });
|
|
56462
|
+
return;
|
|
56463
|
+
}
|
|
56464
|
+
const include = includeParsed.value;
|
|
56465
|
+
const globalParsed = parseBooleanLike(req.query.global);
|
|
56466
|
+
if (!globalParsed.ok) {
|
|
56467
|
+
res.status(400).json({ error: `global ${globalParsed.error}` });
|
|
56468
|
+
return;
|
|
56469
|
+
}
|
|
56470
|
+
const globalParam = globalParsed.value === true;
|
|
56471
|
+
const sourceParsed = parseConfigSource(req.query.source);
|
|
56472
|
+
if (!sourceParsed.ok) {
|
|
56473
|
+
res.status(400).json({ error: sourceParsed.error || "Invalid source value" });
|
|
56474
|
+
return;
|
|
56475
|
+
}
|
|
56476
|
+
const configSource = sourceParsed.value;
|
|
56477
|
+
const discovered = await discoverMigrationItems(include, configSource);
|
|
56478
|
+
const registry = await readPortableRegistry();
|
|
56479
|
+
const candidates = [];
|
|
56480
|
+
if (include.agents) {
|
|
56481
|
+
addCandidates(discovered.agents.map((a3) => ({
|
|
56482
|
+
name: a3.name,
|
|
56483
|
+
description: a3.description,
|
|
56484
|
+
sourcePath: a3.sourcePath ?? ""
|
|
56485
|
+
})), "agent", false);
|
|
56486
|
+
}
|
|
56487
|
+
if (include.commands) {
|
|
56488
|
+
addCandidates(discovered.commands.map((c2) => ({
|
|
56489
|
+
name: c2.name,
|
|
56490
|
+
description: c2.description,
|
|
56491
|
+
sourcePath: c2.sourcePath ?? ""
|
|
56492
|
+
})), "command", false);
|
|
56493
|
+
}
|
|
56494
|
+
if (include.skills) {
|
|
56495
|
+
addCandidates(discovered.skills.map((s) => ({
|
|
56496
|
+
name: s.name,
|
|
56497
|
+
description: s.description,
|
|
56498
|
+
path: s.path
|
|
56499
|
+
})), "skill", true);
|
|
56500
|
+
}
|
|
56501
|
+
if (include.config && discovered.configItem) {
|
|
56502
|
+
addCandidates([
|
|
56503
|
+
{
|
|
56504
|
+
name: discovered.configItem.name,
|
|
56505
|
+
description: undefined,
|
|
56506
|
+
sourcePath: discovered.configItem.sourcePath ?? ""
|
|
56507
|
+
}
|
|
56508
|
+
], "config", false);
|
|
56509
|
+
}
|
|
56510
|
+
if (include.rules) {
|
|
56511
|
+
addCandidates(discovered.ruleItems.map((r2) => ({
|
|
56512
|
+
name: r2.name,
|
|
56513
|
+
description: undefined,
|
|
56514
|
+
sourcePath: r2.sourcePath ?? ""
|
|
56515
|
+
})), "rules", false);
|
|
56516
|
+
}
|
|
56517
|
+
if (include.hooks) {
|
|
56518
|
+
addCandidates(discovered.hookItems.map((h2) => ({
|
|
56519
|
+
name: h2.name,
|
|
56520
|
+
description: undefined,
|
|
56521
|
+
sourcePath: h2.sourcePath ?? ""
|
|
56522
|
+
})), "hooks", false);
|
|
56523
|
+
}
|
|
56524
|
+
const providerConfigs = selectedProviders.map((provider) => ({
|
|
56525
|
+
provider,
|
|
56526
|
+
global: globalParam
|
|
56527
|
+
}));
|
|
56528
|
+
const enabledTypes = ["agent", "command", "skill", "config", "rules", "hooks"].filter((type) => {
|
|
56529
|
+
const key = type === "agent" ? "agents" : type === "command" ? "commands" : type === "skill" ? "skills" : type === "config" ? "config" : type === "rules" ? "rules" : "hooks";
|
|
56530
|
+
return include[key];
|
|
56531
|
+
});
|
|
56532
|
+
const typeDirectoryStates = buildTypeDirectoryStates(providerConfigs, enabledTypes);
|
|
56533
|
+
res.status(200).json({ candidates, typeDirectoryStates });
|
|
56534
|
+
} catch (error) {
|
|
56535
|
+
res.status(500).json({
|
|
56536
|
+
error: "Failed to discover install candidates",
|
|
56537
|
+
message: sanitizeUntrusted(error, 260)
|
|
56538
|
+
});
|
|
56539
|
+
}
|
|
56540
|
+
});
|
|
56089
56541
|
app.post("/api/migrate/execute", async (req, res) => {
|
|
56090
56542
|
try {
|
|
56091
56543
|
const planBased = req.body?.plan !== undefined;
|
|
@@ -56488,7 +56940,7 @@ function registerMigrationRoutes(app) {
|
|
|
56488
56940
|
}
|
|
56489
56941
|
});
|
|
56490
56942
|
}
|
|
56491
|
-
var MIGRATION_TYPES, MAX_PROVIDER_COUNT = 20, MAX_PLAN_ACTIONS = 5000, ALLOWED_CONFIG_SOURCE_KEYS, CONFLICT_RESOLUTION_SCHEMA, RECONCILE_ACTION_SCHEMA, RECONCILE_PLAN_SCHEMA, PLAN_EXECUTE_PAYLOAD_SCHEMA, PLURAL_TO_SINGULAR, shellHookWarningShown = false;
|
|
56943
|
+
var MIGRATION_TYPES, MAX_PROVIDER_COUNT = 20, MAX_PLAN_ACTIONS = 5000, ALLOWED_CONFIG_SOURCE_KEYS, CONFLICT_RESOLUTION_SCHEMA, RECONCILE_ACTION_SCHEMA, RECONCILE_BANNER_SCHEMA, RECONCILE_PLAN_SCHEMA, PLAN_EXECUTE_PAYLOAD_SCHEMA, PLURAL_TO_SINGULAR, shellHookWarningShown = false;
|
|
56492
56944
|
var init_migration_routes = __esm(() => {
|
|
56493
56945
|
init_agents_discovery();
|
|
56494
56946
|
init_commands_discovery();
|
|
@@ -56540,8 +56992,20 @@ var init_migration_routes = __esm(() => {
|
|
|
56540
56992
|
ownedSections: exports_external.array(exports_external.string()).optional(),
|
|
56541
56993
|
affectedSections: exports_external.array(exports_external.string()).optional(),
|
|
56542
56994
|
diff: exports_external.string().optional(),
|
|
56543
|
-
resolution: CONFLICT_RESOLUTION_SCHEMA.optional()
|
|
56995
|
+
resolution: CONFLICT_RESOLUTION_SCHEMA.optional(),
|
|
56996
|
+
reasonCode: exports_external.string().optional(),
|
|
56997
|
+
reasonCopy: exports_external.string().optional(),
|
|
56998
|
+
isDirectoryItem: exports_external.boolean().optional()
|
|
56544
56999
|
}).passthrough();
|
|
57000
|
+
RECONCILE_BANNER_SCHEMA = exports_external.object({
|
|
57001
|
+
kind: exports_external.enum(["empty-dir", "empty-dir-respected"]),
|
|
57002
|
+
provider: exports_external.string(),
|
|
57003
|
+
type: exports_external.string(),
|
|
57004
|
+
global: exports_external.boolean(),
|
|
57005
|
+
path: exports_external.string(),
|
|
57006
|
+
itemCount: exports_external.number().int().nonnegative(),
|
|
57007
|
+
message: exports_external.string()
|
|
57008
|
+
});
|
|
56545
57009
|
RECONCILE_PLAN_SCHEMA = exports_external.object({
|
|
56546
57010
|
actions: exports_external.array(RECONCILE_ACTION_SCHEMA).max(MAX_PLAN_ACTIONS),
|
|
56547
57011
|
summary: exports_external.object({
|
|
@@ -56551,11 +57015,13 @@ var init_migration_routes = __esm(() => {
|
|
|
56551
57015
|
conflict: exports_external.number().int().nonnegative(),
|
|
56552
57016
|
delete: exports_external.number().int().nonnegative()
|
|
56553
57017
|
}),
|
|
56554
|
-
hasConflicts: exports_external.boolean()
|
|
57018
|
+
hasConflicts: exports_external.boolean(),
|
|
57019
|
+
banners: exports_external.array(RECONCILE_BANNER_SCHEMA).optional().default([])
|
|
56555
57020
|
}).passthrough();
|
|
56556
57021
|
PLAN_EXECUTE_PAYLOAD_SCHEMA = exports_external.object({
|
|
56557
57022
|
plan: RECONCILE_PLAN_SCHEMA,
|
|
56558
|
-
resolutions: exports_external.record(CONFLICT_RESOLUTION_SCHEMA).optional().default({})
|
|
57023
|
+
resolutions: exports_external.record(CONFLICT_RESOLUTION_SCHEMA).optional().default({}),
|
|
57024
|
+
mode: exports_external.enum(["reconcile", "install"]).optional()
|
|
56559
57025
|
}).passthrough();
|
|
56560
57026
|
PLURAL_TO_SINGULAR = {
|
|
56561
57027
|
agents: "agent",
|
|
@@ -56568,7 +57034,7 @@ var init_migration_routes = __esm(() => {
|
|
|
56568
57034
|
});
|
|
56569
57035
|
|
|
56570
57036
|
// src/domains/plan-parser/plan-metadata.ts
|
|
56571
|
-
import { readFileSync as readFileSync6, statSync as
|
|
57037
|
+
import { readFileSync as readFileSync6, statSync as statSync6 } from "node:fs";
|
|
56572
57038
|
function readMatter(filePath) {
|
|
56573
57039
|
try {
|
|
56574
57040
|
return import_gray_matter6.default(readFileSync6(filePath, "utf8")).data;
|
|
@@ -56645,7 +57111,7 @@ function parseEffortHours(value) {
|
|
|
56645
57111
|
}
|
|
56646
57112
|
function readPlanMetadata(planFile, counts) {
|
|
56647
57113
|
const frontmatter = readMatter(planFile);
|
|
56648
|
-
const stats =
|
|
57114
|
+
const stats = statSync6(planFile);
|
|
56649
57115
|
return {
|
|
56650
57116
|
title: typeof frontmatter.title === "string" ? frontmatter.title : undefined,
|
|
56651
57117
|
description: typeof frontmatter.description === "string" ? frontmatter.description : undefined,
|
|
@@ -56662,7 +57128,7 @@ function readPlanMetadata(planFile, counts) {
|
|
|
56662
57128
|
}
|
|
56663
57129
|
function readPhaseMetadata(phaseFile) {
|
|
56664
57130
|
const frontmatter = readMatter(phaseFile);
|
|
56665
|
-
const stats =
|
|
57131
|
+
const stats = statSync6(phaseFile);
|
|
56666
57132
|
return {
|
|
56667
57133
|
title: typeof frontmatter.title === "string" ? frontmatter.title : undefined,
|
|
56668
57134
|
status: normalizePhaseStatus(frontmatter.status),
|
|
@@ -57059,7 +57525,7 @@ var init_plan_table_parser = __esm(() => {
|
|
|
57059
57525
|
|
|
57060
57526
|
// src/domains/plan-parser/activity-tracker.ts
|
|
57061
57527
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
57062
|
-
import { readdirSync as
|
|
57528
|
+
import { readdirSync as readdirSync4, statSync as statSync7 } from "node:fs";
|
|
57063
57529
|
import { join as join42, relative as relative8 } from "node:path";
|
|
57064
57530
|
function startOfDay(date) {
|
|
57065
57531
|
const copy = new Date(date);
|
|
@@ -57069,7 +57535,7 @@ function startOfDay(date) {
|
|
|
57069
57535
|
function enumerateMarkdownFiles(dir, depth = 0) {
|
|
57070
57536
|
if (depth >= MAX_DEPTH)
|
|
57071
57537
|
return [];
|
|
57072
|
-
const entries =
|
|
57538
|
+
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
57073
57539
|
return entries.flatMap((entry) => {
|
|
57074
57540
|
const entryPath = join42(dir, entry.name);
|
|
57075
57541
|
if (entry.isDirectory())
|
|
@@ -57113,7 +57579,7 @@ function getGitSamples(dir, samples) {
|
|
|
57113
57579
|
}
|
|
57114
57580
|
function getMtimeSamples(dir, samples) {
|
|
57115
57581
|
for (const file of enumerateMarkdownFiles(dir)) {
|
|
57116
|
-
const mtimeKey = startOfDay(
|
|
57582
|
+
const mtimeKey = startOfDay(statSync7(file).mtime).toISOString();
|
|
57117
57583
|
const sample = samples.get(mtimeKey);
|
|
57118
57584
|
if (!sample)
|
|
57119
57585
|
continue;
|
|
@@ -57176,13 +57642,13 @@ var DAY_MS = 86400000, CELL_COUNT = 84, MAX_DEPTH = 10;
|
|
|
57176
57642
|
var init_activity_tracker = () => {};
|
|
57177
57643
|
|
|
57178
57644
|
// src/domains/plan-parser/plan-scanner.ts
|
|
57179
|
-
import { existsSync as existsSync29, readdirSync as
|
|
57645
|
+
import { existsSync as existsSync29, readdirSync as readdirSync5 } from "node:fs";
|
|
57180
57646
|
import { join as join43 } from "node:path";
|
|
57181
57647
|
function scanPlanDir(dir) {
|
|
57182
57648
|
if (!existsSync29(dir))
|
|
57183
57649
|
return [];
|
|
57184
57650
|
try {
|
|
57185
|
-
return
|
|
57651
|
+
return readdirSync5(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join43(dir, entry.name, "plan.md")).filter(existsSync29);
|
|
57186
57652
|
} catch {
|
|
57187
57653
|
return [];
|
|
57188
57654
|
}
|
|
@@ -60228,7 +60694,7 @@ var init_skill_browser_routes = __esm(() => {
|
|
|
60228
60694
|
});
|
|
60229
60695
|
|
|
60230
60696
|
// src/commands/skills/agents.ts
|
|
60231
|
-
import { existsSync as existsSync37, readdirSync as
|
|
60697
|
+
import { existsSync as existsSync37, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
60232
60698
|
import { homedir as homedir37, platform as platform5 } from "node:os";
|
|
60233
60699
|
import { join as join54 } from "node:path";
|
|
60234
60700
|
function hasInstallSignal2(path6) {
|
|
@@ -60236,9 +60702,9 @@ function hasInstallSignal2(path6) {
|
|
|
60236
60702
|
return false;
|
|
60237
60703
|
}
|
|
60238
60704
|
try {
|
|
60239
|
-
const stat10 =
|
|
60705
|
+
const stat10 = statSync8(path6);
|
|
60240
60706
|
if (stat10.isDirectory()) {
|
|
60241
|
-
return
|
|
60707
|
+
return readdirSync6(path6).length > 0;
|
|
60242
60708
|
}
|
|
60243
60709
|
if (stat10.isFile()) {
|
|
60244
60710
|
return true;
|
|
@@ -61617,7 +62083,7 @@ var package_default;
|
|
|
61617
62083
|
var init_package = __esm(() => {
|
|
61618
62084
|
package_default = {
|
|
61619
62085
|
name: "claudekit-cli",
|
|
61620
|
-
version: "3.41.4-dev.
|
|
62086
|
+
version: "3.41.4-dev.49",
|
|
61621
62087
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
61622
62088
|
type: "module",
|
|
61623
62089
|
repository: {
|
|
@@ -61660,6 +62126,8 @@ var init_package = __esm(() => {
|
|
|
61660
62126
|
"test:integration": "CK_RUN_CLI_INTEGRATION=1 bun test tests/integration/cli.test.ts",
|
|
61661
62127
|
"test:watch": "bun test --watch",
|
|
61662
62128
|
"test:quick": "./scripts/dev-quick-start.sh test",
|
|
62129
|
+
"test:e2e": "playwright test --config=playwright.config.ts",
|
|
62130
|
+
"test:e2e:ui": "playwright test --ui --config=playwright.config.ts",
|
|
61663
62131
|
lint: "biome check .",
|
|
61664
62132
|
"lint:fix": "biome check --fix .",
|
|
61665
62133
|
"lint:fix-unsafe": "biome check --fix --unsafe .",
|
|
@@ -61718,6 +62186,7 @@ var init_package = __esm(() => {
|
|
|
61718
62186
|
},
|
|
61719
62187
|
devDependencies: {
|
|
61720
62188
|
"@biomejs/biome": "^1.9.4",
|
|
62189
|
+
"@playwright/test": "^1.59.1",
|
|
61721
62190
|
"@semantic-release/changelog": "^6.0.3",
|
|
61722
62191
|
"@semantic-release/git": "^10.0.1",
|
|
61723
62192
|
"@tauri-apps/cli": "^2",
|
|
@@ -72915,7 +73384,7 @@ var init_content_validator = __esm(() => {
|
|
|
72915
73384
|
|
|
72916
73385
|
// src/commands/content/phases/context-cache-manager.ts
|
|
72917
73386
|
import { createHash as createHash9 } from "node:crypto";
|
|
72918
|
-
import { existsSync as existsSync75, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as
|
|
73387
|
+
import { existsSync as existsSync75, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync14 } from "node:fs";
|
|
72919
73388
|
import { rename as rename14, writeFile as writeFile38 } from "node:fs/promises";
|
|
72920
73389
|
import { homedir as homedir52 } from "node:os";
|
|
72921
73390
|
import { basename as basename30, join as join158 } from "node:path";
|
|
@@ -72951,7 +73420,7 @@ function computeSourceHash(repoPath) {
|
|
|
72951
73420
|
const paths = getDocSourcePaths(repoPath);
|
|
72952
73421
|
for (const filePath of paths) {
|
|
72953
73422
|
try {
|
|
72954
|
-
const stat25 =
|
|
73423
|
+
const stat25 = statSync14(filePath);
|
|
72955
73424
|
hash.update(`${filePath}:${stat25.mtimeMs}`);
|
|
72956
73425
|
} catch {
|
|
72957
73426
|
hash.update(`${filePath}:0`);
|
|
@@ -72964,7 +73433,7 @@ function getDocSourcePaths(repoPath) {
|
|
|
72964
73433
|
const docsDir = join158(repoPath, "docs");
|
|
72965
73434
|
if (existsSync75(docsDir)) {
|
|
72966
73435
|
try {
|
|
72967
|
-
const files =
|
|
73436
|
+
const files = readdirSync11(docsDir);
|
|
72968
73437
|
for (const f3 of files) {
|
|
72969
73438
|
if (f3.endsWith(".md"))
|
|
72970
73439
|
paths.push(join158(docsDir, f3));
|
|
@@ -72977,7 +73446,7 @@ function getDocSourcePaths(repoPath) {
|
|
|
72977
73446
|
const stylesDir = join158(repoPath, "assets", "writing-styles");
|
|
72978
73447
|
if (existsSync75(stylesDir)) {
|
|
72979
73448
|
try {
|
|
72980
|
-
const files =
|
|
73449
|
+
const files = readdirSync11(stylesDir);
|
|
72981
73450
|
for (const f3 of files) {
|
|
72982
73451
|
paths.push(join158(stylesDir, f3));
|
|
72983
73452
|
}
|
|
@@ -73172,7 +73641,7 @@ function extractContentFromResponse(response) {
|
|
|
73172
73641
|
|
|
73173
73642
|
// src/commands/content/phases/docs-summarizer.ts
|
|
73174
73643
|
import { execSync as execSync7 } from "node:child_process";
|
|
73175
|
-
import { existsSync as existsSync76, readFileSync as readFileSync19, readdirSync as
|
|
73644
|
+
import { existsSync as existsSync76, readFileSync as readFileSync19, readdirSync as readdirSync12 } from "node:fs";
|
|
73176
73645
|
import { join as join159 } from "node:path";
|
|
73177
73646
|
async function summarizeProjectDocs(repoPath, contentLogger) {
|
|
73178
73647
|
const rawContent = collectRawDocs(repoPath);
|
|
@@ -73230,7 +73699,7 @@ function collectRawDocs(repoPath) {
|
|
|
73230
73699
|
const docsDir = join159(repoPath, "docs");
|
|
73231
73700
|
if (existsSync76(docsDir)) {
|
|
73232
73701
|
try {
|
|
73233
|
-
const files =
|
|
73702
|
+
const files = readdirSync12(docsDir).filter((f3) => f3.endsWith(".md")).sort();
|
|
73234
73703
|
for (const f3 of files) {
|
|
73235
73704
|
const content = readCapped(join159(docsDir, f3), 5000);
|
|
73236
73705
|
if (content) {
|
|
@@ -73254,7 +73723,7 @@ ${content}`);
|
|
|
73254
73723
|
const stylesDir = join159(repoPath, "assets", "writing-styles");
|
|
73255
73724
|
if (existsSync76(stylesDir)) {
|
|
73256
73725
|
try {
|
|
73257
|
-
const files =
|
|
73726
|
+
const files = readdirSync12(stylesDir).slice(0, 3);
|
|
73258
73727
|
styles3 = files.map((f3) => readCapped(join159(stylesDir, f3), 1000)).filter(Boolean).join(`
|
|
73259
73728
|
|
|
73260
73729
|
`);
|
|
@@ -73445,7 +73914,7 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
|
|
|
73445
73914
|
|
|
73446
73915
|
// src/commands/content/phases/photo-generator.ts
|
|
73447
73916
|
import { execSync as execSync8 } from "node:child_process";
|
|
73448
|
-
import { existsSync as existsSync77, mkdirSync as mkdirSync6, readdirSync as
|
|
73917
|
+
import { existsSync as existsSync77, mkdirSync as mkdirSync6, readdirSync as readdirSync13 } from "node:fs";
|
|
73449
73918
|
import { homedir as homedir53 } from "node:os";
|
|
73450
73919
|
import { join as join160 } from "node:path";
|
|
73451
73920
|
async function generatePhoto(_content, context, config, platform17, contentId, contentLogger) {
|
|
@@ -73470,7 +73939,7 @@ async function generatePhoto(_content, context, config, platform17, contentId, c
|
|
|
73470
73939
|
return { path: imagePath, ...dimensions, format: "png" };
|
|
73471
73940
|
}
|
|
73472
73941
|
}
|
|
73473
|
-
const files =
|
|
73942
|
+
const files = readdirSync13(mediaDir);
|
|
73474
73943
|
const imageFile = files.find((f3) => /\.(png|jpg|jpeg|webp)$/i.test(f3));
|
|
73475
73944
|
if (imageFile) {
|
|
73476
73945
|
const ext2 = imageFile.split(".").pop() ?? "png";
|
|
@@ -73562,7 +74031,7 @@ var init_content_creator = __esm(() => {
|
|
|
73562
74031
|
});
|
|
73563
74032
|
|
|
73564
74033
|
// src/commands/content/phases/content-logger.ts
|
|
73565
|
-
import { createWriteStream as createWriteStream4, existsSync as existsSync78, mkdirSync as mkdirSync7, statSync as
|
|
74034
|
+
import { createWriteStream as createWriteStream4, existsSync as existsSync78, mkdirSync as mkdirSync7, statSync as statSync15 } from "node:fs";
|
|
73566
74035
|
import { homedir as homedir54 } from "node:os";
|
|
73567
74036
|
import { join as join161 } from "node:path";
|
|
73568
74037
|
|
|
@@ -73628,7 +74097,7 @@ class ContentLogger {
|
|
|
73628
74097
|
if (this.maxBytes > 0 && this.stream) {
|
|
73629
74098
|
const logPath = join161(this.logDir, `content-${this.currentDate}.log`);
|
|
73630
74099
|
try {
|
|
73631
|
-
const stat25 =
|
|
74100
|
+
const stat25 = statSync15(logPath);
|
|
73632
74101
|
if (stat25.size >= this.maxBytes) {
|
|
73633
74102
|
this.close();
|
|
73634
74103
|
const suffix = Date.now();
|
|
@@ -73857,7 +74326,7 @@ function isNoiseCommit(title, author) {
|
|
|
73857
74326
|
|
|
73858
74327
|
// src/commands/content/phases/change-detector.ts
|
|
73859
74328
|
import { execSync as execSync10, spawnSync as spawnSync9 } from "node:child_process";
|
|
73860
|
-
import { existsSync as existsSync80, readFileSync as readFileSync20, readdirSync as
|
|
74329
|
+
import { existsSync as existsSync80, readFileSync as readFileSync20, readdirSync as readdirSync14, statSync as statSync16 } from "node:fs";
|
|
73861
74330
|
import { join as join162 } from "node:path";
|
|
73862
74331
|
function detectCommits(repo, since) {
|
|
73863
74332
|
try {
|
|
@@ -73973,7 +74442,7 @@ function detectCompletedPlans(repo, since) {
|
|
|
73973
74442
|
const sinceMs = new Date(since).getTime();
|
|
73974
74443
|
const events = [];
|
|
73975
74444
|
try {
|
|
73976
|
-
const entries =
|
|
74445
|
+
const entries = readdirSync14(plansDir, { withFileTypes: true });
|
|
73977
74446
|
for (const entry of entries) {
|
|
73978
74447
|
if (!entry.isDirectory())
|
|
73979
74448
|
continue;
|
|
@@ -73981,7 +74450,7 @@ function detectCompletedPlans(repo, since) {
|
|
|
73981
74450
|
if (!existsSync80(planFile))
|
|
73982
74451
|
continue;
|
|
73983
74452
|
try {
|
|
73984
|
-
const stat25 =
|
|
74453
|
+
const stat25 = statSync16(planFile);
|
|
73985
74454
|
if (stat25.mtimeMs < sinceMs)
|
|
73986
74455
|
continue;
|
|
73987
74456
|
const content = readFileSync20(planFile, "utf-8");
|
|
@@ -74054,7 +74523,7 @@ function classifyCommit(event) {
|
|
|
74054
74523
|
|
|
74055
74524
|
// src/commands/content/phases/repo-discoverer.ts
|
|
74056
74525
|
import { execSync as execSync11 } from "node:child_process";
|
|
74057
|
-
import { readdirSync as
|
|
74526
|
+
import { readdirSync as readdirSync15 } from "node:fs";
|
|
74058
74527
|
import { join as join163 } from "node:path";
|
|
74059
74528
|
function discoverRepos2(cwd2) {
|
|
74060
74529
|
const repos = [];
|
|
@@ -74064,7 +74533,7 @@ function discoverRepos2(cwd2) {
|
|
|
74064
74533
|
repos.push(info);
|
|
74065
74534
|
}
|
|
74066
74535
|
try {
|
|
74067
|
-
const entries =
|
|
74536
|
+
const entries = readdirSync15(cwd2, { withFileTypes: true });
|
|
74068
74537
|
for (const entry of entries) {
|
|
74069
74538
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
74070
74539
|
continue;
|
|
@@ -76774,19 +77243,40 @@ var init_migrate_command_help = __esm(() => {
|
|
|
76774
77243
|
usage: "ck migrate [options]",
|
|
76775
77244
|
examples: [
|
|
76776
77245
|
{
|
|
76777
|
-
command: "ck migrate --
|
|
76778
|
-
description: "
|
|
77246
|
+
command: "ck migrate --install",
|
|
77247
|
+
description: "Pick items to install interactively (install picker mode)"
|
|
76779
77248
|
},
|
|
76780
77249
|
{
|
|
76781
|
-
command: "ck migrate --agent codex -
|
|
76782
|
-
description: "
|
|
77250
|
+
command: "ck migrate --agent codex --dry-run",
|
|
77251
|
+
description: "Preview the destination-aware reconcile plan before writing files"
|
|
76783
77252
|
},
|
|
76784
77253
|
{
|
|
76785
|
-
command: "
|
|
76786
|
-
description: "
|
|
77254
|
+
command: "ck migrate --respect-deletions",
|
|
77255
|
+
description: "Preserve empty directories — do not auto-reinstall deleted items"
|
|
76787
77256
|
}
|
|
76788
77257
|
],
|
|
76789
77258
|
optionGroups: [
|
|
77259
|
+
{
|
|
77260
|
+
title: "Mode Options",
|
|
77261
|
+
options: [
|
|
77262
|
+
{
|
|
77263
|
+
flags: "--install",
|
|
77264
|
+
description: "Opt-in install picker mode — interactively select which items to install (default when registry is empty or has unknown checksums)"
|
|
77265
|
+
},
|
|
77266
|
+
{
|
|
77267
|
+
flags: "--reconcile",
|
|
77268
|
+
description: "Force reconcile mode — compute diff vs registry and apply only changes (default when registry is valid)"
|
|
77269
|
+
},
|
|
77270
|
+
{
|
|
77271
|
+
flags: "--reinstall-empty-dirs",
|
|
77272
|
+
description: "Reinstall all items when their type directory is empty or missing (default: true). Use --respect-deletions to disable."
|
|
77273
|
+
},
|
|
77274
|
+
{
|
|
77275
|
+
flags: "--respect-deletions",
|
|
77276
|
+
description: "Preserve deletion even when a type directory is empty — skip reinstall heuristic. Mutually exclusive with --reinstall-empty-dirs."
|
|
77277
|
+
}
|
|
77278
|
+
]
|
|
77279
|
+
},
|
|
76790
77280
|
{
|
|
76791
77281
|
title: "Target Options",
|
|
76792
77282
|
options: [
|
|
@@ -76849,6 +77339,19 @@ var init_migrate_command_help = __esm(() => {
|
|
|
76849
77339
|
}
|
|
76850
77340
|
]
|
|
76851
77341
|
}
|
|
77342
|
+
],
|
|
77343
|
+
sections: [
|
|
77344
|
+
{
|
|
77345
|
+
title: "Gotchas",
|
|
77346
|
+
content: [
|
|
77347
|
+
" --install and --reconcile are mutually exclusive — pass only one",
|
|
77348
|
+
" --reinstall-empty-dirs and --respect-deletions are mutually exclusive — pass only one",
|
|
77349
|
+
" Default mode is smart-detected: no/stale registry → install, valid registry → reconcile",
|
|
77350
|
+
" --respect-deletions disables the auto-reinstall heuristic for empty directories",
|
|
77351
|
+
" --force overrides skip decisions per item; --reinstall-empty-dirs is a per-directory heuristic"
|
|
77352
|
+
].join(`
|
|
77353
|
+
`)
|
|
77354
|
+
}
|
|
76852
77355
|
]
|
|
76853
77356
|
};
|
|
76854
77357
|
});
|
|
@@ -84326,7 +84829,7 @@ async function checkCliInstallMethod() {
|
|
|
84326
84829
|
};
|
|
84327
84830
|
}
|
|
84328
84831
|
// src/domains/health-checks/checkers/claude-md-checker.ts
|
|
84329
|
-
import { existsSync as existsSync48, statSync as
|
|
84832
|
+
import { existsSync as existsSync48, statSync as statSync9 } from "node:fs";
|
|
84330
84833
|
import { join as join76 } from "node:path";
|
|
84331
84834
|
function checkClaudeMd(setup, projectDir) {
|
|
84332
84835
|
const results = [];
|
|
@@ -84352,7 +84855,7 @@ function checkClaudeMdFile(path6, name, id) {
|
|
|
84352
84855
|
};
|
|
84353
84856
|
}
|
|
84354
84857
|
try {
|
|
84355
|
-
const stat13 =
|
|
84858
|
+
const stat13 = statSync9(path6);
|
|
84356
84859
|
const sizeKB = (stat13.size / 1024).toFixed(1);
|
|
84357
84860
|
if (stat13.size === 0) {
|
|
84358
84861
|
return {
|
|
@@ -85363,7 +85866,7 @@ init_command_normalizer();
|
|
|
85363
85866
|
init_logger();
|
|
85364
85867
|
init_path_resolver();
|
|
85365
85868
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
85366
|
-
import { existsSync as existsSync55, readFileSync as readFileSync15, statSync as
|
|
85869
|
+
import { existsSync as existsSync55, readFileSync as readFileSync15, statSync as statSync10, writeFileSync as writeFileSync5 } from "node:fs";
|
|
85367
85870
|
import { readdir as readdir21 } from "node:fs/promises";
|
|
85368
85871
|
import { homedir as homedir43, tmpdir as tmpdir2 } from "node:os";
|
|
85369
85872
|
import { join as join86, resolve as resolve30 } from "node:path";
|
|
@@ -86211,7 +86714,7 @@ async function checkHookLogs(projectDir) {
|
|
|
86211
86714
|
};
|
|
86212
86715
|
}
|
|
86213
86716
|
try {
|
|
86214
|
-
const logStats =
|
|
86717
|
+
const logStats = statSync10(logPath);
|
|
86215
86718
|
if (logStats.size > MAX_LOG_FILE_SIZE_BYTES) {
|
|
86216
86719
|
return {
|
|
86217
86720
|
id: "hook-logs",
|
|
@@ -98253,7 +98756,7 @@ async function handleDownload(ctx) {
|
|
|
98253
98756
|
import { join as join122 } from "node:path";
|
|
98254
98757
|
|
|
98255
98758
|
// src/domains/installation/deletion-handler.ts
|
|
98256
|
-
import { existsSync as existsSync61, lstatSync as lstatSync3, readdirSync as
|
|
98759
|
+
import { existsSync as existsSync61, lstatSync as lstatSync3, readdirSync as readdirSync7, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync4 } from "node:fs";
|
|
98257
98760
|
import { dirname as dirname35, join as join108, relative as relative17, resolve as resolve34, sep as sep10 } from "node:path";
|
|
98258
98761
|
|
|
98259
98762
|
// src/services/file-operations/manifest/manifest-reader.ts
|
|
@@ -98447,7 +98950,7 @@ function collectFilesRecursively(dir, baseDir) {
|
|
|
98447
98950
|
if (!existsSync61(dir))
|
|
98448
98951
|
return results;
|
|
98449
98952
|
try {
|
|
98450
|
-
const entries =
|
|
98953
|
+
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
98451
98954
|
for (const entry of entries) {
|
|
98452
98955
|
const fullPath = join108(dir, entry.name);
|
|
98453
98956
|
const relativePath = relative17(baseDir, fullPath);
|
|
@@ -98485,7 +98988,7 @@ function cleanupEmptyDirectories(filePath, claudeDir3) {
|
|
|
98485
98988
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir) && iterations < MAX_CLEANUP_ITERATIONS) {
|
|
98486
98989
|
iterations++;
|
|
98487
98990
|
try {
|
|
98488
|
-
const entries =
|
|
98991
|
+
const entries = readdirSync7(currentDir);
|
|
98489
98992
|
if (entries.length === 0) {
|
|
98490
98993
|
rmdirSync(currentDir);
|
|
98491
98994
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
@@ -104163,7 +104666,7 @@ async function runPreflightChecks() {
|
|
|
104163
104666
|
|
|
104164
104667
|
// src/domains/installation/fresh-installer.ts
|
|
104165
104668
|
init_metadata_migration();
|
|
104166
|
-
import { existsSync as existsSync63, readdirSync as
|
|
104669
|
+
import { existsSync as existsSync63, readdirSync as readdirSync8, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
|
|
104167
104670
|
import { basename as basename24, dirname as dirname39, join as join134, resolve as resolve36 } from "node:path";
|
|
104168
104671
|
init_logger();
|
|
104169
104672
|
init_safe_spinner();
|
|
@@ -104216,7 +104719,7 @@ function cleanupEmptyDirectories2(filePath, claudeDir3) {
|
|
|
104216
104719
|
let currentDir = resolve36(dirname39(filePath));
|
|
104217
104720
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
|
|
104218
104721
|
try {
|
|
104219
|
-
const entries =
|
|
104722
|
+
const entries = readdirSync8(currentDir);
|
|
104220
104723
|
if (entries.length === 0) {
|
|
104221
104724
|
rmdirSync2(currentDir);
|
|
104222
104725
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
@@ -106916,6 +107419,30 @@ function buildProviderScopeSubtitle(selectedProviders, global3) {
|
|
|
106916
107419
|
}
|
|
106917
107420
|
return `${selectedProviders.length} providers -> ${scope}`;
|
|
106918
107421
|
}
|
|
107422
|
+
function renderBannerLines(banner) {
|
|
107423
|
+
const width = 64;
|
|
107424
|
+
const bar = `+${"=".repeat(width)}+`;
|
|
107425
|
+
const homePath = process.env.HOME ?? "";
|
|
107426
|
+
const displayPath = banner.path.replace(homePath, "~");
|
|
107427
|
+
if (banner.kind === "empty-dir") {
|
|
107428
|
+
return [
|
|
107429
|
+
bar,
|
|
107430
|
+
`| [i] Detected empty ${displayPath}`,
|
|
107431
|
+
`| ${banner.itemCount} item(s) below will be reinstalled.`,
|
|
107432
|
+
"| Use --respect-deletions to preserve deletion.",
|
|
107433
|
+
bar
|
|
107434
|
+
];
|
|
107435
|
+
}
|
|
107436
|
+
if (banner.kind === "empty-dir-respected") {
|
|
107437
|
+
return [
|
|
107438
|
+
bar,
|
|
107439
|
+
`| [i] Detected empty ${displayPath}`,
|
|
107440
|
+
`| ${banner.itemCount} item(s) skipped (--respect-deletions active).`,
|
|
107441
|
+
bar
|
|
107442
|
+
];
|
|
107443
|
+
}
|
|
107444
|
+
return [];
|
|
107445
|
+
}
|
|
106919
107446
|
function buildSourceSummaryLines(counts, origins) {
|
|
106920
107447
|
const parts = [];
|
|
106921
107448
|
if (counts.agents > 0)
|
|
@@ -106939,6 +107466,148 @@ function buildSourceSummaryLines(counts, origins) {
|
|
|
106939
107466
|
|
|
106940
107467
|
// src/commands/migrate/migrate-command.ts
|
|
106941
107468
|
init_skill_directory_installer();
|
|
107469
|
+
function validateMutualExclusion(options2) {
|
|
107470
|
+
if (options2.install && options2.reconcile) {
|
|
107471
|
+
return "Pass either --install or --reconcile, not both.";
|
|
107472
|
+
}
|
|
107473
|
+
if (options2.reinstallEmptyDirs && options2.respectDeletions) {
|
|
107474
|
+
return "Pass either --reinstall-empty-dirs or --respect-deletions, not both.";
|
|
107475
|
+
}
|
|
107476
|
+
return null;
|
|
107477
|
+
}
|
|
107478
|
+
function resolveMigrationMode(options2, hasUnknownChecksums) {
|
|
107479
|
+
if (options2.install)
|
|
107480
|
+
return "install";
|
|
107481
|
+
if (options2.reconcile)
|
|
107482
|
+
return "reconcile";
|
|
107483
|
+
if (hasUnknownChecksums)
|
|
107484
|
+
return "install";
|
|
107485
|
+
return "reconcile";
|
|
107486
|
+
}
|
|
107487
|
+
function renderBanners(banners) {
|
|
107488
|
+
if (banners.length === 0)
|
|
107489
|
+
return;
|
|
107490
|
+
for (const banner of banners) {
|
|
107491
|
+
const lines = renderBannerLines(banner);
|
|
107492
|
+
if (lines.length > 0) {
|
|
107493
|
+
console.log();
|
|
107494
|
+
for (const line of lines) {
|
|
107495
|
+
console.log(line);
|
|
107496
|
+
}
|
|
107497
|
+
}
|
|
107498
|
+
}
|
|
107499
|
+
}
|
|
107500
|
+
async function runInstallMode(options2, discoveredItems, _selectedProviders, _installGlobally) {
|
|
107501
|
+
const interactive = process.stdout.isTTY && !options2.yes;
|
|
107502
|
+
if (!interactive) {
|
|
107503
|
+
return discoveredItems;
|
|
107504
|
+
}
|
|
107505
|
+
const toOption = (item) => ({
|
|
107506
|
+
value: item.name,
|
|
107507
|
+
label: item.name,
|
|
107508
|
+
hint: item.recommended ? "Recommended" : undefined
|
|
107509
|
+
});
|
|
107510
|
+
let selectedAgents = discoveredItems.agents;
|
|
107511
|
+
let selectedCommands = discoveredItems.commands;
|
|
107512
|
+
let selectedSkills = discoveredItems.skills;
|
|
107513
|
+
let selectedConfig = discoveredItems.configItem;
|
|
107514
|
+
let selectedRules = discoveredItems.ruleItems;
|
|
107515
|
+
let selectedHooks = discoveredItems.hookItems;
|
|
107516
|
+
if (discoveredItems.agents.length > 0) {
|
|
107517
|
+
const picked = await ae({
|
|
107518
|
+
message: `Select agents to install (${discoveredItems.agents.length} available)`,
|
|
107519
|
+
options: discoveredItems.agents.map(toOption),
|
|
107520
|
+
initialValues: discoveredItems.agents.map((a3) => a3.name),
|
|
107521
|
+
required: false
|
|
107522
|
+
});
|
|
107523
|
+
if (lD(picked)) {
|
|
107524
|
+
ue("Migrate cancelled");
|
|
107525
|
+
process.exit(0);
|
|
107526
|
+
}
|
|
107527
|
+
const pickedSet = new Set(picked);
|
|
107528
|
+
selectedAgents = discoveredItems.agents.filter((a3) => pickedSet.has(a3.name));
|
|
107529
|
+
}
|
|
107530
|
+
if (discoveredItems.commands.length > 0) {
|
|
107531
|
+
const picked = await ae({
|
|
107532
|
+
message: `Select commands to install (${discoveredItems.commands.length} available)`,
|
|
107533
|
+
options: discoveredItems.commands.map(toOption),
|
|
107534
|
+
initialValues: discoveredItems.commands.map((c2) => c2.name),
|
|
107535
|
+
required: false
|
|
107536
|
+
});
|
|
107537
|
+
if (lD(picked)) {
|
|
107538
|
+
ue("Migrate cancelled");
|
|
107539
|
+
process.exit(0);
|
|
107540
|
+
}
|
|
107541
|
+
const pickedSet = new Set(picked);
|
|
107542
|
+
selectedCommands = discoveredItems.commands.filter((c2) => pickedSet.has(c2.name));
|
|
107543
|
+
}
|
|
107544
|
+
if (discoveredItems.skills.length > 0) {
|
|
107545
|
+
const picked = await ae({
|
|
107546
|
+
message: `Select skills to install (${discoveredItems.skills.length} available, directory-level)`,
|
|
107547
|
+
options: discoveredItems.skills.map((s) => ({
|
|
107548
|
+
value: s.name,
|
|
107549
|
+
label: s.name,
|
|
107550
|
+
hint: "skill directory"
|
|
107551
|
+
})),
|
|
107552
|
+
initialValues: discoveredItems.skills.map((s) => s.name),
|
|
107553
|
+
required: false
|
|
107554
|
+
});
|
|
107555
|
+
if (lD(picked)) {
|
|
107556
|
+
ue("Migrate cancelled");
|
|
107557
|
+
process.exit(0);
|
|
107558
|
+
}
|
|
107559
|
+
const pickedSet = new Set(picked);
|
|
107560
|
+
selectedSkills = discoveredItems.skills.filter((s) => pickedSet.has(s.name));
|
|
107561
|
+
}
|
|
107562
|
+
if (discoveredItems.configItem) {
|
|
107563
|
+
const include = await se({
|
|
107564
|
+
message: "Include CLAUDE.md config?",
|
|
107565
|
+
initialValue: true
|
|
107566
|
+
});
|
|
107567
|
+
if (lD(include)) {
|
|
107568
|
+
ue("Migrate cancelled");
|
|
107569
|
+
process.exit(0);
|
|
107570
|
+
}
|
|
107571
|
+
if (!include)
|
|
107572
|
+
selectedConfig = null;
|
|
107573
|
+
}
|
|
107574
|
+
if (discoveredItems.ruleItems.length > 0) {
|
|
107575
|
+
const picked = await ae({
|
|
107576
|
+
message: `Select rules to install (${discoveredItems.ruleItems.length} available)`,
|
|
107577
|
+
options: discoveredItems.ruleItems.map(toOption),
|
|
107578
|
+
initialValues: discoveredItems.ruleItems.map((r2) => r2.name),
|
|
107579
|
+
required: false
|
|
107580
|
+
});
|
|
107581
|
+
if (lD(picked)) {
|
|
107582
|
+
ue("Migrate cancelled");
|
|
107583
|
+
process.exit(0);
|
|
107584
|
+
}
|
|
107585
|
+
const pickedSet = new Set(picked);
|
|
107586
|
+
selectedRules = discoveredItems.ruleItems.filter((r2) => pickedSet.has(r2.name));
|
|
107587
|
+
}
|
|
107588
|
+
if (discoveredItems.hookItems.length > 0) {
|
|
107589
|
+
const picked = await ae({
|
|
107590
|
+
message: `Select hooks to install (${discoveredItems.hookItems.length} available)`,
|
|
107591
|
+
options: discoveredItems.hookItems.map(toOption),
|
|
107592
|
+
initialValues: discoveredItems.hookItems.map((h2) => h2.name),
|
|
107593
|
+
required: false
|
|
107594
|
+
});
|
|
107595
|
+
if (lD(picked)) {
|
|
107596
|
+
ue("Migrate cancelled");
|
|
107597
|
+
process.exit(0);
|
|
107598
|
+
}
|
|
107599
|
+
const pickedSet = new Set(picked);
|
|
107600
|
+
selectedHooks = discoveredItems.hookItems.filter((h2) => pickedSet.has(h2.name));
|
|
107601
|
+
}
|
|
107602
|
+
return {
|
|
107603
|
+
agents: selectedAgents,
|
|
107604
|
+
commands: selectedCommands,
|
|
107605
|
+
skills: selectedSkills,
|
|
107606
|
+
configItem: selectedConfig,
|
|
107607
|
+
ruleItems: selectedRules,
|
|
107608
|
+
hookItems: selectedHooks
|
|
107609
|
+
};
|
|
107610
|
+
}
|
|
106942
107611
|
function getProviderPathKey(type) {
|
|
106943
107612
|
switch (type) {
|
|
106944
107613
|
case "agent":
|
|
@@ -106953,8 +107622,6 @@ function getProviderPathKey(type) {
|
|
|
106953
107622
|
return "hooks";
|
|
106954
107623
|
case "skill":
|
|
106955
107624
|
return "skills";
|
|
106956
|
-
default:
|
|
106957
|
-
return type;
|
|
106958
107625
|
}
|
|
106959
107626
|
}
|
|
106960
107627
|
function shouldExecuteAction2(action) {
|
|
@@ -107036,6 +107703,11 @@ function inferKitTypeFromSourceMetadata(sourceMetadata) {
|
|
|
107036
107703
|
}
|
|
107037
107704
|
async function migrateCommand(options2) {
|
|
107038
107705
|
console.log();
|
|
107706
|
+
const mutexError = validateMutualExclusion(options2);
|
|
107707
|
+
if (mutexError) {
|
|
107708
|
+
f2.error(mutexError);
|
|
107709
|
+
process.exit(1);
|
|
107710
|
+
}
|
|
107039
107711
|
try {
|
|
107040
107712
|
const scope = resolveMigrationScope(process.argv.slice(2), options2);
|
|
107041
107713
|
const spinner = de();
|
|
@@ -107229,31 +107901,66 @@ async function migrateCommand(options2) {
|
|
|
107229
107901
|
setTaxonomyOverrides(ckConfigResult.config.modelTaxonomy);
|
|
107230
107902
|
const reconcileSpinner = de();
|
|
107231
107903
|
reconcileSpinner.start("Computing migration plan...");
|
|
107904
|
+
const registry = await readPortableRegistry();
|
|
107905
|
+
const hasUnknownChecksums = registry.installations.some((entry) => !entry.sourceChecksum || entry.sourceChecksum === "unknown" || !entry.targetChecksum || entry.targetChecksum === "unknown");
|
|
107906
|
+
const migrationMode = resolveMigrationMode(options2, hasUnknownChecksums);
|
|
107907
|
+
let effectiveAgents = agents2;
|
|
107908
|
+
let effectiveCommands = commands;
|
|
107909
|
+
let effectiveSkills = skills;
|
|
107910
|
+
let effectiveConfigItem = configItem;
|
|
107911
|
+
let effectiveRuleItems = ruleItems;
|
|
107912
|
+
let effectiveHookItems = hookItems;
|
|
107913
|
+
if (migrationMode === "install") {
|
|
107914
|
+
reconcileSpinner.stop("Discovery complete");
|
|
107915
|
+
if (!options2.yes && process.stdout.isTTY) {
|
|
107916
|
+
f2.info(`[i] Smart default: ${hasUnknownChecksums ? "unknown checksums detected" : "--install flag"} — entering install picker mode.`);
|
|
107917
|
+
}
|
|
107918
|
+
const picked = await runInstallMode(options2, {
|
|
107919
|
+
agents: agents2,
|
|
107920
|
+
commands,
|
|
107921
|
+
skills,
|
|
107922
|
+
configItem,
|
|
107923
|
+
ruleItems,
|
|
107924
|
+
hookItems
|
|
107925
|
+
}, selectedProviders, installGlobally);
|
|
107926
|
+
effectiveAgents = picked.agents;
|
|
107927
|
+
effectiveCommands = picked.commands;
|
|
107928
|
+
effectiveSkills = picked.skills;
|
|
107929
|
+
effectiveConfigItem = picked.configItem;
|
|
107930
|
+
effectiveRuleItems = picked.ruleItems;
|
|
107931
|
+
effectiveHookItems = picked.hookItems;
|
|
107932
|
+
reconcileSpinner.start("Computing migration plan...");
|
|
107933
|
+
}
|
|
107232
107934
|
const sourceStates = await computeSourceStates({
|
|
107233
|
-
agents:
|
|
107234
|
-
commands,
|
|
107235
|
-
config:
|
|
107236
|
-
rules:
|
|
107237
|
-
hooks:
|
|
107935
|
+
agents: effectiveAgents,
|
|
107936
|
+
commands: effectiveCommands,
|
|
107937
|
+
config: effectiveConfigItem,
|
|
107938
|
+
rules: effectiveRuleItems,
|
|
107939
|
+
hooks: effectiveHookItems
|
|
107238
107940
|
}, selectedProviders);
|
|
107239
107941
|
const targetStates = await computeTargetStates(selectedProviders, installGlobally);
|
|
107240
|
-
const registry = await readPortableRegistry();
|
|
107241
107942
|
const providerConfigs = selectedProviders.map((provider) => ({
|
|
107242
107943
|
provider,
|
|
107243
107944
|
global: installGlobally
|
|
107244
107945
|
}));
|
|
107946
|
+
const portableTypes = ["agent", "command", "config", "rules", "hooks"];
|
|
107947
|
+
const typeDirectoryStates = buildTypeDirectoryStates(selectedProviders.map((provider) => ({ provider, global: installGlobally })), [...portableTypes]);
|
|
107948
|
+
const reinstallEmptyDirs = options2.respectDeletions ? false : options2.reinstallEmptyDirs ?? true;
|
|
107245
107949
|
const plan = reconcile({
|
|
107246
107950
|
sourceItems: sourceStates,
|
|
107247
107951
|
registry,
|
|
107248
107952
|
targetStates,
|
|
107249
107953
|
providerConfigs,
|
|
107250
|
-
force: options2.force
|
|
107954
|
+
force: options2.force,
|
|
107955
|
+
typeDirectoryStates,
|
|
107956
|
+
respectDeletions: !reinstallEmptyDirs
|
|
107251
107957
|
});
|
|
107252
107958
|
reconcileSpinner.stop("Plan computed");
|
|
107253
107959
|
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
107960
|
+
renderBanners(plan.banners);
|
|
107254
107961
|
displayReconcilePlan(plan, { color: useColor });
|
|
107255
107962
|
if (options2.dryRun) {
|
|
107256
|
-
displayMigrationSummary(plan, buildDryRunFallbackResults(
|
|
107963
|
+
displayMigrationSummary(plan, buildDryRunFallbackResults(effectiveSkills, selectedProviders, installGlobally, plan.actions), { color: useColor, dryRun: true });
|
|
107257
107964
|
return;
|
|
107258
107965
|
}
|
|
107259
107966
|
if (plan.hasConflicts) {
|
|
@@ -107263,7 +107970,7 @@ async function migrateCommand(options2) {
|
|
|
107263
107970
|
if (!action.diff && action.targetPath && existsSync64(action.targetPath)) {
|
|
107264
107971
|
try {
|
|
107265
107972
|
const targetContent = await readFile61(action.targetPath, "utf-8");
|
|
107266
|
-
const sourceItem =
|
|
107973
|
+
const sourceItem = effectiveAgents.find((a3) => a3.name === action.item) || effectiveCommands.find((c2) => c2.name === action.item) || (effectiveConfigItem?.name === action.item ? effectiveConfigItem : null) || effectiveRuleItems.find((r2) => r2.name === action.item) || effectiveHookItems.find((h2) => h2.name === action.item);
|
|
107267
107974
|
if (sourceItem) {
|
|
107268
107975
|
const providerConfig = providers[action.provider];
|
|
107269
107976
|
const pathConfigKey = getProviderPathKey(action.type);
|
|
@@ -107301,12 +108008,12 @@ async function migrateCommand(options2) {
|
|
|
107301
108008
|
}
|
|
107302
108009
|
let allResults = [];
|
|
107303
108010
|
const installOpts = { global: installGlobally };
|
|
107304
|
-
const agentByName = new Map(
|
|
107305
|
-
const commandByName = new Map(
|
|
107306
|
-
const skillByName = new Map(
|
|
107307
|
-
const configByName = new Map(
|
|
107308
|
-
const ruleByName = new Map(
|
|
107309
|
-
const hookByName = new Map(
|
|
108011
|
+
const agentByName = new Map(effectiveAgents.map((item) => [item.name, item]));
|
|
108012
|
+
const commandByName = new Map(effectiveCommands.map((item) => [item.name, item]));
|
|
108013
|
+
const skillByName = new Map(effectiveSkills.map((item) => [item.name, item]));
|
|
108014
|
+
const configByName = new Map(effectiveConfigItem ? [[effectiveConfigItem.name, effectiveConfigItem]] : []);
|
|
108015
|
+
const ruleByName = new Map(effectiveRuleItems.map((item) => [item.name, item]));
|
|
108016
|
+
const hookByName = new Map(effectiveHookItems.map((item) => [item.name, item]));
|
|
107310
108017
|
const successfulHookFiles = new Map;
|
|
107311
108018
|
const successfulHookAbsPaths = new Map;
|
|
107312
108019
|
const postProgressWarnings = [];
|
|
@@ -107358,10 +108065,10 @@ async function migrateCommand(options2) {
|
|
|
107358
108065
|
}
|
|
107359
108066
|
}
|
|
107360
108067
|
const plannedSkillActions = plannedExecActions.filter((action) => action.type === "skill").length;
|
|
107361
|
-
if (
|
|
108068
|
+
if (effectiveSkills.length > 0 && plannedSkillActions === 0) {
|
|
107362
108069
|
const skillProviders = selectedProviders.filter((pv) => getProvidersSupporting("skills").includes(pv));
|
|
107363
108070
|
for (const provider of skillProviders) {
|
|
107364
|
-
for (const skill of
|
|
108071
|
+
for (const skill of effectiveSkills) {
|
|
107365
108072
|
writeTasks.push({ item: skill, provider, type: "skill" });
|
|
107366
108073
|
}
|
|
107367
108074
|
}
|
|
@@ -108069,7 +108776,7 @@ Please use only one download method.`);
|
|
|
108069
108776
|
}
|
|
108070
108777
|
// src/commands/plan/plan-command.ts
|
|
108071
108778
|
init_output_manager();
|
|
108072
|
-
import { existsSync as existsSync67, statSync as
|
|
108779
|
+
import { existsSync as existsSync67, statSync as statSync12 } from "node:fs";
|
|
108073
108780
|
import { dirname as dirname46, isAbsolute as isAbsolute11, join as join147, parse as parse7, resolve as resolve45 } from "node:path";
|
|
108074
108781
|
|
|
108075
108782
|
// src/commands/plan/plan-read-handlers.ts
|
|
@@ -108079,7 +108786,7 @@ init_plans_registry();
|
|
|
108079
108786
|
init_logger();
|
|
108080
108787
|
init_output_manager();
|
|
108081
108788
|
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
108082
|
-
import { existsSync as existsSync66, statSync as
|
|
108789
|
+
import { existsSync as existsSync66, statSync as statSync11 } from "node:fs";
|
|
108083
108790
|
import { basename as basename27, dirname as dirname44, join as join146, relative as relative27, resolve as resolve43 } from "node:path";
|
|
108084
108791
|
|
|
108085
108792
|
// src/commands/plan/plan-dependencies.ts
|
|
@@ -108249,7 +108956,7 @@ async function handleStatus(target, options2) {
|
|
|
108249
108956
|
}
|
|
108250
108957
|
const effectiveTarget = !resolvedTarget && globalBaseDir ? globalBaseDir : resolvedTarget;
|
|
108251
108958
|
const t = effectiveTarget ? resolve43(effectiveTarget) : null;
|
|
108252
|
-
const plansDir = t && existsSync66(t) &&
|
|
108959
|
+
const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(join146(t, "plan.md")) ? t : null;
|
|
108253
108960
|
if (plansDir) {
|
|
108254
108961
|
const planFiles = scanPlanDir(plansDir);
|
|
108255
108962
|
if (planFiles.length === 0) {
|
|
@@ -108661,7 +109368,7 @@ function resolveTargetPath(target, baseDir) {
|
|
|
108661
109368
|
function resolvePlanFile(target, baseDir) {
|
|
108662
109369
|
const t = target ? resolveTargetPath(target, baseDir) : baseDir ? resolve45(baseDir) : process.cwd();
|
|
108663
109370
|
if (existsSync67(t)) {
|
|
108664
|
-
const stat23 =
|
|
109371
|
+
const stat23 = statSync12(t);
|
|
108665
109372
|
if (stat23.isFile())
|
|
108666
109373
|
return t;
|
|
108667
109374
|
const candidate = join147(t, "plan.md");
|
|
@@ -109874,7 +110581,7 @@ async function detectInstallations() {
|
|
|
109874
110581
|
}
|
|
109875
110582
|
|
|
109876
110583
|
// src/commands/uninstall/removal-handler.ts
|
|
109877
|
-
import { readdirSync as
|
|
110584
|
+
import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
|
|
109878
110585
|
import { basename as basename29, join as join150, resolve as resolve47, sep as sep12 } from "node:path";
|
|
109879
110586
|
init_logger();
|
|
109880
110587
|
init_safe_prompts();
|
|
@@ -109883,7 +110590,7 @@ var import_fs_extra44 = __toESM(require_lib3(), 1);
|
|
|
109883
110590
|
|
|
109884
110591
|
// src/commands/uninstall/analysis-handler.ts
|
|
109885
110592
|
init_metadata_migration();
|
|
109886
|
-
import { readdirSync as
|
|
110593
|
+
import { readdirSync as readdirSync9, rmSync as rmSync4 } from "node:fs";
|
|
109887
110594
|
import { dirname as dirname47, join as join149 } from "node:path";
|
|
109888
110595
|
init_logger();
|
|
109889
110596
|
init_safe_prompts();
|
|
@@ -109909,7 +110616,7 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
|
109909
110616
|
let currentDir = dirname47(filePath);
|
|
109910
110617
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
109911
110618
|
try {
|
|
109912
|
-
const entries =
|
|
110619
|
+
const entries = readdirSync9(currentDir);
|
|
109913
110620
|
if (entries.length === 0) {
|
|
109914
110621
|
rmSync4(currentDir, { recursive: true });
|
|
109915
110622
|
cleaned++;
|
|
@@ -110150,7 +110857,7 @@ async function removeInstallations(installations, options2) {
|
|
|
110150
110857
|
}
|
|
110151
110858
|
}
|
|
110152
110859
|
try {
|
|
110153
|
-
const remaining =
|
|
110860
|
+
const remaining = readdirSync10(installation.path);
|
|
110154
110861
|
if (remaining.length === 0) {
|
|
110155
110862
|
rmSync5(installation.path, { recursive: true });
|
|
110156
110863
|
logger.debug(`Removed empty installation directory: ${installation.path}`);
|
|
@@ -112003,7 +112710,7 @@ Run this command from a directory with a GitHub remote.`);
|
|
|
112003
112710
|
// src/commands/watch/phases/watch-logger.ts
|
|
112004
112711
|
init_logger();
|
|
112005
112712
|
init_path_resolver();
|
|
112006
|
-
import { createWriteStream as createWriteStream3, statSync as
|
|
112713
|
+
import { createWriteStream as createWriteStream3, statSync as statSync13 } from "node:fs";
|
|
112007
112714
|
import { existsSync as existsSync73 } from "node:fs";
|
|
112008
112715
|
import { mkdir as mkdir38, rename as rename13 } from "node:fs/promises";
|
|
112009
112716
|
import { join as join156 } from "node:path";
|
|
@@ -112071,7 +112778,7 @@ class WatchLogger {
|
|
|
112071
112778
|
return;
|
|
112072
112779
|
if (this.maxBytes > 0 && this.logPath) {
|
|
112073
112780
|
try {
|
|
112074
|
-
const stats =
|
|
112781
|
+
const stats = statSync13(this.logPath);
|
|
112075
112782
|
if (stats.size >= this.maxBytes) {
|
|
112076
112783
|
this.rotateLog();
|
|
112077
112784
|
}
|
|
@@ -112449,7 +113156,7 @@ function registerCommands(cli) {
|
|
|
112449
113156
|
cli.command("api [action] [service] [path]", "Interact with ClaudeKit API and proxy services").option("--method <method>", "HTTP method for proxy requests (default: GET)").option("--body <json>", "Request body as JSON string (proxy only)").option("--query <json>", "Query params as JSON string (proxy only)").option("--key <key>", "API key to use (setup only)").option("--force", "Force re-setup even if key exists (setup only)").option("--json", "Output raw JSON instead of formatted display").option("--locale <locale>", "Locale for vidcap summary/caption (default: en)").option("--max-results <n>", "Max results for vidcap search").option("--second <s>", "Timestamp in seconds for vidcap screenshot").option("--order <order>", "Sort order for vidcap comments (time/relevance)").option("--format <fmt>", "Summary format for reviewweb (bullet/paragraph)").option("--max-length <n>", "Max summary length for reviewweb").option("--instructions <text>", "Extraction instructions for reviewweb extract").option("--template <json>", "JSON template for reviewweb extract").option("--type <type>", "Link type filter for reviewweb links (web/image/file/all)").option("--country <code>", "Country code for reviewweb SEO commands").action(async (action, service, path16, options2) => {
|
|
112450
113157
|
await apiCommand(action, service, path16, options2);
|
|
112451
113158
|
});
|
|
112452
|
-
cli.command("migrate", "Migrate agents, commands, skills, config, rules, and hooks to other providers").option("-a, --agent <agents...>", "Target providers (cursor, codex, droid, opencode, etc.)").option("-g, --global", "Install globally instead of project-level").option("--all", "Migrate to all supported providers").option("-y, --yes", "Skip confirmation prompts").option("--config", "Migrate CLAUDE.md config only").option("--rules", "Migrate .claude/rules/ only").option("--hooks", "Migrate .claude/hooks/ only").option("--skip-config", "Skip config migration").option("--skip-rules", "Skip rules migration").option("--skip-hooks", "Skip hooks migration").option("--source <path>", "Custom CLAUDE.md source path (config only, not agents/commands/skills/hooks)").option("--dry-run", "Preview migration targets without writing files").option("-f, --force", "Force reinstall deleted/edited items").action(async (options2) => {
|
|
113159
|
+
cli.command("migrate", "Migrate agents, commands, skills, config, rules, and hooks to other providers").option("-a, --agent <agents...>", "Target providers (cursor, codex, droid, opencode, etc.)").option("-g, --global", "Install globally instead of project-level").option("--all", "Migrate to all supported providers").option("-y, --yes", "Skip confirmation prompts").option("--config", "Migrate CLAUDE.md config only").option("--rules", "Migrate .claude/rules/ only").option("--hooks", "Migrate .claude/hooks/ only").option("--skip-config", "Skip config migration").option("--skip-rules", "Skip rules migration").option("--skip-hooks", "Skip hooks migration").option("--source <path>", "Custom CLAUDE.md source path (config only, not agents/commands/skills/hooks)").option("--dry-run", "Preview migration targets without writing files").option("-f, --force", "Force reinstall deleted/edited items").option("--install", "Opt-in install picker mode (select specific items to install)").option("--reconcile", "Force reconcile mode (current default when registry is valid)").option("--reinstall-empty-dirs", "Reinstall all items when their type directory is empty (default: true)").option("--respect-deletions", "Preserve deletion even when type directory is empty (disables reinstall-empty-dirs)").action(async (options2) => {
|
|
112453
113160
|
if (options2.agent && !Array.isArray(options2.agent)) {
|
|
112454
113161
|
options2.agent = [options2.agent];
|
|
112455
113162
|
}
|