@smicolon/ai-kit 0.5.1 → 0.5.2
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 +150 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -679,6 +679,114 @@ function isSymlink(p3) {
|
|
|
679
679
|
return false;
|
|
680
680
|
}
|
|
681
681
|
}
|
|
682
|
+
function findOrphans(pack, projectDir) {
|
|
683
|
+
const orphans = [];
|
|
684
|
+
const canonicalBase = path5.join(projectDir, CANONICAL_SKILLS_DIR);
|
|
685
|
+
for (const sourceSkillDir of pack.skills) {
|
|
686
|
+
const skillName = path5.basename(sourceSkillDir);
|
|
687
|
+
const canonicalDest = path5.join(canonicalBase, skillName);
|
|
688
|
+
if (skillDirMatchesSource(canonicalDest, sourceSkillDir)) {
|
|
689
|
+
orphans.push(canonicalDest);
|
|
690
|
+
}
|
|
691
|
+
for (const toolId of TOOL_IDS) {
|
|
692
|
+
const toolSkillsDir = TOOL_REGISTRY[toolId].components.skills;
|
|
693
|
+
if (!toolSkillsDir) continue;
|
|
694
|
+
const linkPath = path5.join(projectDir, toolSkillsDir, skillName);
|
|
695
|
+
if (path5.resolve(linkPath) === path5.resolve(canonicalDest)) continue;
|
|
696
|
+
if (symlinkPointsInto(linkPath, canonicalDest)) {
|
|
697
|
+
orphans.push(linkPath);
|
|
698
|
+
} else if (!isSymlink(linkPath) && skillDirMatchesSource(linkPath, sourceSkillDir)) {
|
|
699
|
+
orphans.push(linkPath);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const collectFiles = (sourceFiles, component) => {
|
|
704
|
+
for (const sourceFile of sourceFiles) {
|
|
705
|
+
const base = path5.basename(sourceFile);
|
|
706
|
+
for (const toolId of TOOL_IDS) {
|
|
707
|
+
const dir = TOOL_REGISTRY[toolId].components[component];
|
|
708
|
+
if (!dir) continue;
|
|
709
|
+
let destPath;
|
|
710
|
+
let expected;
|
|
711
|
+
if (component === "rules" && toolId === "cursor") {
|
|
712
|
+
const mdcName = path5.basename(sourceFile, ".md") + ".mdc";
|
|
713
|
+
destPath = path5.join(projectDir, dir, mdcName);
|
|
714
|
+
expected = Buffer.from(convertToMdc(sourceFile, pack.name));
|
|
715
|
+
if (fileContentEquals(destPath, expected)) orphans.push(destPath);
|
|
716
|
+
const legacyPath = path5.join(projectDir, dir, base);
|
|
717
|
+
try {
|
|
718
|
+
const legacyExpected = fs6.readFileSync(sourceFile);
|
|
719
|
+
if (fileContentEquals(legacyPath, legacyExpected)) {
|
|
720
|
+
orphans.push(legacyPath);
|
|
721
|
+
}
|
|
722
|
+
} catch {
|
|
723
|
+
}
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
destPath = path5.join(projectDir, dir, base);
|
|
727
|
+
try {
|
|
728
|
+
expected = fs6.readFileSync(sourceFile);
|
|
729
|
+
} catch {
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
if (fileContentEquals(destPath, expected)) {
|
|
733
|
+
orphans.push(destPath);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
collectFiles(pack.agents, "agents");
|
|
739
|
+
collectFiles(pack.commands, "commands");
|
|
740
|
+
collectFiles(pack.rules, "rules");
|
|
741
|
+
return [...new Set(orphans)];
|
|
742
|
+
}
|
|
743
|
+
function fileContentEquals(filePath, expected) {
|
|
744
|
+
try {
|
|
745
|
+
if (!fs6.existsSync(filePath) || isSymlink(filePath)) return false;
|
|
746
|
+
const stat = fs6.statSync(filePath);
|
|
747
|
+
if (!stat.isFile()) return false;
|
|
748
|
+
return fs6.readFileSync(filePath).equals(expected);
|
|
749
|
+
} catch {
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function symlinkPointsInto(linkPath, expectedDir) {
|
|
754
|
+
try {
|
|
755
|
+
if (!isSymlink(linkPath)) return false;
|
|
756
|
+
const resolved = path5.resolve(path5.dirname(linkPath), fs6.readlinkSync(linkPath));
|
|
757
|
+
return path5.resolve(resolved) === path5.resolve(expectedDir);
|
|
758
|
+
} catch {
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function skillDirMatchesSource(destDir, sourceDir) {
|
|
763
|
+
if (!fs6.existsSync(destDir) || isSymlink(destDir)) return false;
|
|
764
|
+
if (!fs6.statSync(destDir).isDirectory()) return false;
|
|
765
|
+
const sourceFiles = collectRelativeFiles(sourceDir);
|
|
766
|
+
const destFiles = collectRelativeFiles(destDir);
|
|
767
|
+
if (sourceFiles.length !== destFiles.length) return false;
|
|
768
|
+
const sourceSet = new Set(sourceFiles);
|
|
769
|
+
for (const f of destFiles) if (!sourceSet.has(f)) return false;
|
|
770
|
+
for (const rel of sourceFiles) {
|
|
771
|
+
const src = fs6.readFileSync(path5.join(sourceDir, rel));
|
|
772
|
+
const dst = fs6.readFileSync(path5.join(destDir, rel));
|
|
773
|
+
if (!src.equals(dst)) return false;
|
|
774
|
+
}
|
|
775
|
+
return true;
|
|
776
|
+
}
|
|
777
|
+
function collectRelativeFiles(dir, base = dir) {
|
|
778
|
+
const out = [];
|
|
779
|
+
if (!fs6.existsSync(dir)) return out;
|
|
780
|
+
for (const entry of fs6.readdirSync(dir, { withFileTypes: true })) {
|
|
781
|
+
const full = path5.join(dir, entry.name);
|
|
782
|
+
if (entry.isDirectory()) {
|
|
783
|
+
out.push(...collectRelativeFiles(full, base));
|
|
784
|
+
} else if (entry.isFile()) {
|
|
785
|
+
out.push(path5.relative(base, full));
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return out.sort();
|
|
789
|
+
}
|
|
682
790
|
|
|
683
791
|
// src/global-config.ts
|
|
684
792
|
import fs7 from "fs";
|
|
@@ -1018,30 +1126,58 @@ ${pc3.dim(`${packs.length} packs available`)}`);
|
|
|
1018
1126
|
import { Command as Command4 } from "commander";
|
|
1019
1127
|
import path9 from "path";
|
|
1020
1128
|
import pc4 from "picocolors";
|
|
1021
|
-
var removeCommand = new Command4("remove").description("Remove a pack from your project").argument("<pack>", "Pack name to remove").option("--cwd <dir>", "Project directory").action((packName, opts) => {
|
|
1129
|
+
var removeCommand = new Command4("remove").description("Remove a pack from your project").argument("<pack>", "Pack name to remove").option("--cwd <dir>", "Project directory").action(async (packName, opts) => {
|
|
1022
1130
|
const projectDir = opts.cwd ? path9.resolve(opts.cwd) : process.cwd();
|
|
1023
1131
|
const config = readConfig(projectDir);
|
|
1024
|
-
|
|
1025
|
-
|
|
1132
|
+
const packConfig = config?.packs[packName];
|
|
1133
|
+
const trackedFiles2 = packConfig?.files ?? [];
|
|
1134
|
+
if (trackedFiles2.length > 0) {
|
|
1135
|
+
const removed2 = removePack2(projectDir, trackedFiles2);
|
|
1136
|
+
console.log(pc4.green(`Removed ${removed2} file(s) for ${packName}`));
|
|
1137
|
+
writeConfig(projectDir, removePack(config, packName));
|
|
1138
|
+
console.log(pc4.dim("Config updated."));
|
|
1026
1139
|
return;
|
|
1027
1140
|
}
|
|
1028
|
-
const
|
|
1029
|
-
if (!
|
|
1141
|
+
const pack = await findPack(packName);
|
|
1142
|
+
if (!pack) {
|
|
1143
|
+
const installed = config && Object.keys(config.packs).length > 0 ? "\nInstalled: " + Object.keys(config.packs).join(", ") : "";
|
|
1030
1144
|
console.error(
|
|
1031
|
-
pc4.red(`Pack "${packName}" is not installed
|
|
1145
|
+
pc4.red(`Pack "${packName}" is not installed and not found in the marketplace.`) + installed
|
|
1032
1146
|
);
|
|
1033
1147
|
process.exit(1);
|
|
1034
1148
|
}
|
|
1035
|
-
const
|
|
1036
|
-
if (
|
|
1037
|
-
console.log(pc4.yellow(
|
|
1149
|
+
const orphans = findOrphans(pack, projectDir);
|
|
1150
|
+
if (packConfig) {
|
|
1151
|
+
console.log(pc4.yellow(
|
|
1152
|
+
`"${packName}" has no tracked files in .ai-kit.json (legacy install).`
|
|
1153
|
+
));
|
|
1154
|
+
}
|
|
1155
|
+
if (orphans.length === 0) {
|
|
1156
|
+
if (packConfig) {
|
|
1157
|
+
writeConfig(projectDir, removePack(config, packName));
|
|
1158
|
+
console.log(pc4.dim("Config entry removed; nothing to clean on disk."));
|
|
1159
|
+
} else {
|
|
1160
|
+
console.log(pc4.dim(`Nothing to remove for "${packName}" \u2014 no tracked entry and no orphan files found.`));
|
|
1161
|
+
}
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
if (!packConfig) {
|
|
1165
|
+
console.log(pc4.yellow(
|
|
1166
|
+
`"${packName}" not in .ai-kit.json \u2014 found ${orphans.length} orphan file(s) to clean up:`
|
|
1167
|
+
));
|
|
1038
1168
|
} else {
|
|
1039
|
-
|
|
1040
|
-
|
|
1169
|
+
console.log(pc4.yellow(`Found ${orphans.length} orphan file(s):`));
|
|
1170
|
+
}
|
|
1171
|
+
for (const p3 of orphans) {
|
|
1172
|
+
console.log(pc4.dim(" " + path9.relative(projectDir, p3)));
|
|
1173
|
+
}
|
|
1174
|
+
const relPaths = orphans.map((p3) => path9.relative(projectDir, p3));
|
|
1175
|
+
const removed = removePack2(projectDir, relPaths);
|
|
1176
|
+
console.log(pc4.green(`Removed ${removed} orphan file(s) for ${packName}`));
|
|
1177
|
+
if (packConfig) {
|
|
1178
|
+
writeConfig(projectDir, removePack(config, packName));
|
|
1179
|
+
console.log(pc4.dim("Config updated."));
|
|
1041
1180
|
}
|
|
1042
|
-
const updated = removePack(config, packName);
|
|
1043
|
-
writeConfig(projectDir, updated);
|
|
1044
|
-
console.log(pc4.dim("Config updated."));
|
|
1045
1181
|
});
|
|
1046
1182
|
|
|
1047
1183
|
// src/commands/update.ts
|