library-skills 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/package.json +1 -1
- package/ts/dist/cli.d.ts +110 -0
- package/ts/dist/cli.js +211 -17
- package/ts/dist/deps.cjs +33 -3
- package/ts/dist/deps.d.cts +3 -1
- package/ts/dist/deps.d.ts +3 -1
- package/ts/dist/deps.js +31 -3
- package/ts/dist/installer.cjs +26 -0
- package/ts/dist/installer.d.cts +6 -1
- package/ts/dist/installer.d.ts +6 -1
- package/ts/dist/installer.js +23 -0
- package/ts/dist/python-env.cjs +62 -0
- package/ts/dist/python-env.js +62 -0
package/README.md
CHANGED
|
@@ -49,11 +49,13 @@ $ npx library-skills
|
|
|
49
49
|
|
|
50
50
|
This will scan the dependencies for the current project, find the installed libraries, and ask you which of their skills you want to install in the project.
|
|
51
51
|
|
|
52
|
-
Then it will
|
|
52
|
+
Then it will ask where to install them and add them as symbolic links, so when you update the libraries, the skills are updated too.
|
|
53
|
+
|
|
54
|
+
By default it selects `.agents/skills`, the agent-neutral target. If the project already has a `.claude/` directory, it selects `.claude/skills` too.
|
|
53
55
|
|
|
54
56
|
/// tip
|
|
55
57
|
|
|
56
|
-
If you are using Claude Code,
|
|
58
|
+
If you are using Claude Code, select `.claude/skills` when asked for installation targets, as Claude Code doesn't support the standard `.agents` directory. For non-interactive installs, add the `--claude` CLI option to install the skills in `.claude/skills` too.
|
|
57
59
|
|
|
58
60
|
///
|
|
59
61
|
|
package/package.json
CHANGED
package/ts/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
|
|
4
|
+
interface Skill {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
path: string;
|
|
8
|
+
packageName: string;
|
|
9
|
+
skillDir: string;
|
|
10
|
+
packageVersion: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface InstallTarget {
|
|
14
|
+
name: string;
|
|
15
|
+
path: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface UvWorkspace {
|
|
19
|
+
root: string;
|
|
20
|
+
members: string[];
|
|
21
|
+
currentMember: string | null;
|
|
22
|
+
}
|
|
23
|
+
interface NodeWorkspace {
|
|
24
|
+
root: string;
|
|
25
|
+
members: string[];
|
|
26
|
+
currentMember: string | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface ProjectContext {
|
|
30
|
+
cwd: string;
|
|
31
|
+
projectRoot: string;
|
|
32
|
+
targetEnvironment: string | null;
|
|
33
|
+
sitePackagesDir: string | null;
|
|
34
|
+
nodeModulesDir: string | null;
|
|
35
|
+
workspace: UvWorkspace | null;
|
|
36
|
+
nodeWorkspace: NodeWorkspace | null;
|
|
37
|
+
workspaceDependencyFiles: string[];
|
|
38
|
+
nodeWorkspaceDependencyFiles: string[];
|
|
39
|
+
dependencyFiles: string[];
|
|
40
|
+
}
|
|
41
|
+
interface InstalledStatus {
|
|
42
|
+
target: InstallTarget;
|
|
43
|
+
name: string;
|
|
44
|
+
type: "symlink" | "directory" | "missing";
|
|
45
|
+
path: string;
|
|
46
|
+
targetPath: string | null;
|
|
47
|
+
status: "up to date" | "broken" | "outdated" | "orphaned" | "name mismatch" | "hand-authored" | "new";
|
|
48
|
+
skill: Skill | null;
|
|
49
|
+
}
|
|
50
|
+
interface GlobalOptions {
|
|
51
|
+
claude?: boolean;
|
|
52
|
+
yes?: boolean;
|
|
53
|
+
check?: boolean;
|
|
54
|
+
all?: boolean;
|
|
55
|
+
skill?: string[];
|
|
56
|
+
}
|
|
57
|
+
interface ListOptions {
|
|
58
|
+
installed?: boolean;
|
|
59
|
+
json?: boolean;
|
|
60
|
+
claude?: boolean;
|
|
61
|
+
all?: boolean;
|
|
62
|
+
}
|
|
63
|
+
interface ScanOptions {
|
|
64
|
+
all?: boolean;
|
|
65
|
+
json?: boolean;
|
|
66
|
+
}
|
|
67
|
+
declare function getProjectContext(cwd?: string): ProjectContext;
|
|
68
|
+
declare function topLevelSkills({ context, skills, includeAll, }: {
|
|
69
|
+
context: ProjectContext;
|
|
70
|
+
skills: Skill[];
|
|
71
|
+
includeAll: boolean;
|
|
72
|
+
}): Skill[];
|
|
73
|
+
declare function displayPath(path: string | null | undefined, projectRoot: string): string;
|
|
74
|
+
declare function printTable(columns: string[], rows: Array<Record<string, string>>): void;
|
|
75
|
+
declare function findCollisions(skills: Skill[]): Set<string>;
|
|
76
|
+
declare function filterInstallableSkills({ skills, selectedNames, includeAll, }: {
|
|
77
|
+
skills: Skill[];
|
|
78
|
+
selectedNames: string[];
|
|
79
|
+
includeAll: boolean;
|
|
80
|
+
}): Skill[];
|
|
81
|
+
declare function installedStatuses({ targets, skills, }: {
|
|
82
|
+
targets: InstallTarget[];
|
|
83
|
+
skills: Skill[];
|
|
84
|
+
}): InstalledStatus[];
|
|
85
|
+
declare function installSelected({ skills, targets, projectRoot, copy, }: {
|
|
86
|
+
skills: Skill[];
|
|
87
|
+
targets: InstallTarget[];
|
|
88
|
+
projectRoot: string;
|
|
89
|
+
copy?: boolean;
|
|
90
|
+
}): number;
|
|
91
|
+
declare function sync(options: GlobalOptions): Promise<void>;
|
|
92
|
+
declare function scanCommand(options: ScanOptions): void;
|
|
93
|
+
declare function listCommand(options: ListOptions): void;
|
|
94
|
+
declare function createProgram(): Command;
|
|
95
|
+
declare function main(argv?: string[]): Promise<void>;
|
|
96
|
+
declare const testing: {
|
|
97
|
+
filterInstallableSkills: typeof filterInstallableSkills;
|
|
98
|
+
findCollisions: typeof findCollisions;
|
|
99
|
+
getProjectContext: typeof getProjectContext;
|
|
100
|
+
installSelected: typeof installSelected;
|
|
101
|
+
installedStatuses: typeof installedStatuses;
|
|
102
|
+
listCommand: typeof listCommand;
|
|
103
|
+
scanCommand: typeof scanCommand;
|
|
104
|
+
sync: typeof sync;
|
|
105
|
+
topLevelSkills: typeof topLevelSkills;
|
|
106
|
+
displayPath: typeof displayPath;
|
|
107
|
+
printTable: typeof printTable;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export { createProgram, main, testing };
|
package/ts/dist/cli.js
CHANGED
|
@@ -522,6 +522,28 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
522
522
|
if (!existsSync2(packageJson)) {
|
|
523
523
|
return null;
|
|
524
524
|
}
|
|
525
|
+
return getNodeTopLevelDepsFromFiles([packageJson]);
|
|
526
|
+
}
|
|
527
|
+
function getNodeTopLevelDepsFromFiles(packageJsonFiles) {
|
|
528
|
+
if (packageJsonFiles.length === 0) {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
const deps = /* @__PURE__ */ new Set();
|
|
532
|
+
let found = false;
|
|
533
|
+
for (const packageJson of packageJsonFiles) {
|
|
534
|
+
if (!existsSync2(packageJson)) {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
const data = readPackageJson(packageJson);
|
|
538
|
+
if (data === null) {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
found = true;
|
|
542
|
+
extractNodeTopLevelDeps(data, deps);
|
|
543
|
+
}
|
|
544
|
+
return found ? deps : null;
|
|
545
|
+
}
|
|
546
|
+
function readPackageJson(packageJson) {
|
|
525
547
|
let data;
|
|
526
548
|
try {
|
|
527
549
|
data = JSON.parse(readFileSync2(packageJson, "utf8"));
|
|
@@ -529,9 +551,11 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
529
551
|
return null;
|
|
530
552
|
}
|
|
531
553
|
if (!isRecord2(data)) {
|
|
532
|
-
return
|
|
554
|
+
return {};
|
|
533
555
|
}
|
|
534
|
-
|
|
556
|
+
return data;
|
|
557
|
+
}
|
|
558
|
+
function extractNodeTopLevelDeps(data, deps) {
|
|
535
559
|
for (const field of [
|
|
536
560
|
"dependencies",
|
|
537
561
|
"devDependencies",
|
|
@@ -546,7 +570,6 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
546
570
|
deps.add(normalizePackageName(packageName));
|
|
547
571
|
}
|
|
548
572
|
}
|
|
549
|
-
return deps;
|
|
550
573
|
}
|
|
551
574
|
function getTopLevelDeps(projectRoot) {
|
|
552
575
|
const dependencySets = [
|
|
@@ -561,6 +584,9 @@ function getTopLevelDeps(projectRoot) {
|
|
|
561
584
|
function getWorkspaceTopLevelDeps(pyprojects) {
|
|
562
585
|
return getPythonTopLevelDepsFromFiles(pyprojects);
|
|
563
586
|
}
|
|
587
|
+
function getNodeWorkspaceTopLevelDeps(packageJsonFiles) {
|
|
588
|
+
return getNodeTopLevelDepsFromFiles(packageJsonFiles);
|
|
589
|
+
}
|
|
564
590
|
function extractDepsFromSpecs(depSpecs, deps) {
|
|
565
591
|
for (const depSpec of depSpecs) {
|
|
566
592
|
if (typeof depSpec !== "string") {
|
|
@@ -634,6 +660,26 @@ function getTargetDirs(projectRoot, options = {}) {
|
|
|
634
660
|
}
|
|
635
661
|
return targets;
|
|
636
662
|
}
|
|
663
|
+
function getAllTargetDirs(projectRoot) {
|
|
664
|
+
return getTargetDirs(projectRoot, { includeClaude: true });
|
|
665
|
+
}
|
|
666
|
+
function getDefaultInstallTargetDirs(projectRoot) {
|
|
667
|
+
const [universal, claude] = getAllTargetDirs(projectRoot);
|
|
668
|
+
const selected = [];
|
|
669
|
+
if (existsSync3(join3(projectRoot, ".agents"))) {
|
|
670
|
+
selected.push(universal);
|
|
671
|
+
}
|
|
672
|
+
if (existsSync3(join3(projectRoot, ".claude"))) {
|
|
673
|
+
selected.push(claude);
|
|
674
|
+
}
|
|
675
|
+
return selected.length > 0 ? selected : [universal];
|
|
676
|
+
}
|
|
677
|
+
function getExistingTargetDirs(projectRoot, options = {}) {
|
|
678
|
+
if (options.includeClaude) {
|
|
679
|
+
return getTargetDirs(projectRoot, { includeClaude: true });
|
|
680
|
+
}
|
|
681
|
+
return getAllTargetDirs(projectRoot).filter((target) => isDirectory2(target.path));
|
|
682
|
+
}
|
|
637
683
|
function installSkill(skill, targetDir, options = {}) {
|
|
638
684
|
const dest = join3(targetDir, skill.name);
|
|
639
685
|
const source = resolve2(skill.skillDir);
|
|
@@ -736,6 +782,26 @@ function findUvWorkspace(cwd) {
|
|
|
736
782
|
}
|
|
737
783
|
return null;
|
|
738
784
|
}
|
|
785
|
+
function findNodeWorkspace(cwd) {
|
|
786
|
+
for (const directory of ancestors(cwd)) {
|
|
787
|
+
const packageJson = `${directory}/package.json`;
|
|
788
|
+
if (!existsSync4(packageJson)) {
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
const data = readPackageJson2(packageJson);
|
|
792
|
+
const memberGlobs = getNodeWorkspaceGlobs(data);
|
|
793
|
+
if (memberGlobs === null) {
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
const members = findNodeWorkspaceMembers(directory, memberGlobs);
|
|
797
|
+
return {
|
|
798
|
+
root: directory,
|
|
799
|
+
members,
|
|
800
|
+
currentMember: findCurrentMember(cwd, members)
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
739
805
|
function workspaceDependencyFiles(workspace) {
|
|
740
806
|
if (workspace.currentMember !== null) {
|
|
741
807
|
return [`${workspace.currentMember}/pyproject.toml`];
|
|
@@ -745,6 +811,15 @@ function workspaceDependencyFiles(workspace) {
|
|
|
745
811
|
...workspace.members.map((member) => `${member}/pyproject.toml`)
|
|
746
812
|
].filter((path) => existsSync4(path));
|
|
747
813
|
}
|
|
814
|
+
function nodeWorkspaceDependencyFiles(workspace) {
|
|
815
|
+
if (workspace.currentMember !== null) {
|
|
816
|
+
return [`${workspace.currentMember}/package.json`];
|
|
817
|
+
}
|
|
818
|
+
return [
|
|
819
|
+
`${workspace.root}/package.json`,
|
|
820
|
+
...workspace.members.map((member) => `${member}/package.json`)
|
|
821
|
+
].filter((path) => existsSync4(path));
|
|
822
|
+
}
|
|
748
823
|
function readPyproject(path) {
|
|
749
824
|
try {
|
|
750
825
|
const data = parse3(readFileSync3(path, "utf8"));
|
|
@@ -753,6 +828,14 @@ function readPyproject(path) {
|
|
|
753
828
|
return {};
|
|
754
829
|
}
|
|
755
830
|
}
|
|
831
|
+
function readPackageJson2(path) {
|
|
832
|
+
try {
|
|
833
|
+
const data = JSON.parse(readFileSync3(path, "utf8"));
|
|
834
|
+
return isRecord3(data) ? data : {};
|
|
835
|
+
} catch {
|
|
836
|
+
return {};
|
|
837
|
+
}
|
|
838
|
+
}
|
|
756
839
|
function hasUvWorkspace(data) {
|
|
757
840
|
const tool = data["tool"];
|
|
758
841
|
if (!isRecord3(tool)) {
|
|
@@ -789,6 +872,36 @@ function findWorkspaceMembers(root, data) {
|
|
|
789
872
|
}
|
|
790
873
|
return [...members].sort();
|
|
791
874
|
}
|
|
875
|
+
function getNodeWorkspaceGlobs(data) {
|
|
876
|
+
const workspaces = data["workspaces"];
|
|
877
|
+
if (Array.isArray(workspaces)) {
|
|
878
|
+
return workspaces.filter((value) => typeof value === "string");
|
|
879
|
+
}
|
|
880
|
+
if (isRecord3(workspaces)) {
|
|
881
|
+
const packages = workspaces["packages"];
|
|
882
|
+
if (Array.isArray(packages)) {
|
|
883
|
+
return packages.filter((value) => typeof value === "string");
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
function findNodeWorkspaceMembers(root, memberGlobs) {
|
|
889
|
+
const includes = memberGlobs.filter((pattern) => !pattern.startsWith("!"));
|
|
890
|
+
const excludes = memberGlobs.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1));
|
|
891
|
+
const members = /* @__PURE__ */ new Set();
|
|
892
|
+
for (const memberGlob of includes) {
|
|
893
|
+
for (const member of expandMemberGlob(root, memberGlob)) {
|
|
894
|
+
const relativePath = relative3(root, member).split(sep).join("/");
|
|
895
|
+
if (isExcluded(relativePath, excludes)) {
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
if (isFile(`${member}/package.json`)) {
|
|
899
|
+
members.add(resolve3(member));
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return [...members].sort();
|
|
904
|
+
}
|
|
792
905
|
function getWorkspaceTable(data) {
|
|
793
906
|
const tool = data["tool"];
|
|
794
907
|
if (!isRecord3(tool)) {
|
|
@@ -896,6 +1009,10 @@ function findProjectRoot(cwd) {
|
|
|
896
1009
|
if (workspace !== null) {
|
|
897
1010
|
return workspace.root;
|
|
898
1011
|
}
|
|
1012
|
+
const nodeWorkspace = findNodeWorkspace(cwd);
|
|
1013
|
+
if (nodeWorkspace !== null) {
|
|
1014
|
+
return nodeWorkspace.root;
|
|
1015
|
+
}
|
|
899
1016
|
for (const directory of ancestors2(cwd)) {
|
|
900
1017
|
if (isFile2(join4(directory, "pyproject.toml")) || isFile2(join4(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2(join4(directory, "package.json")) || isDirectory4(join4(directory, "node_modules"))) {
|
|
901
1018
|
return directory;
|
|
@@ -1023,7 +1140,10 @@ function isDirectory4(path) {
|
|
|
1023
1140
|
// ts/src/cli.ts
|
|
1024
1141
|
function getProjectContext(cwd = process.cwd()) {
|
|
1025
1142
|
const workspace = findUvWorkspace(cwd);
|
|
1026
|
-
const
|
|
1143
|
+
const nodeWorkspace = findNodeWorkspace(cwd);
|
|
1144
|
+
const projectRoot = workspace?.root ?? nodeWorkspace?.root ?? findProjectRoot(cwd) ?? cwd;
|
|
1145
|
+
const workspaceFiles = workspace === null ? [] : workspaceDependencyFiles(workspace);
|
|
1146
|
+
const nodeWorkspaceFiles = nodeWorkspace === null ? [] : nodeWorkspaceDependencyFiles(nodeWorkspace);
|
|
1027
1147
|
const targetEnvironment = findVenv(cwd);
|
|
1028
1148
|
const sitePackagesDir = targetEnvironment === null ? null : getSitePackagesDir(targetEnvironment);
|
|
1029
1149
|
const nodeModulesDir = findNodeModules(cwd);
|
|
@@ -1034,7 +1154,10 @@ function getProjectContext(cwd = process.cwd()) {
|
|
|
1034
1154
|
sitePackagesDir,
|
|
1035
1155
|
nodeModulesDir,
|
|
1036
1156
|
workspace,
|
|
1037
|
-
|
|
1157
|
+
nodeWorkspace,
|
|
1158
|
+
workspaceDependencyFiles: workspaceFiles,
|
|
1159
|
+
nodeWorkspaceDependencyFiles: nodeWorkspaceFiles,
|
|
1160
|
+
dependencyFiles: [...workspaceFiles, ...nodeWorkspaceFiles]
|
|
1038
1161
|
};
|
|
1039
1162
|
}
|
|
1040
1163
|
function scanContext(context) {
|
|
@@ -1077,8 +1200,8 @@ function topLevelSkills({
|
|
|
1077
1200
|
return skills;
|
|
1078
1201
|
}
|
|
1079
1202
|
const topLevelDeps = getTopLevelDeps(context.projectRoot);
|
|
1080
|
-
const workspaceTopLevelDeps =
|
|
1081
|
-
const selectedTopLevelDeps = context.workspace === null ? topLevelDeps : workspaceTopLevelDeps;
|
|
1203
|
+
const workspaceTopLevelDeps = getWorkspaceTopLevelDepsForContext(context);
|
|
1204
|
+
const selectedTopLevelDeps = context.workspace === null && context.nodeWorkspace === null ? topLevelDeps : workspaceTopLevelDeps;
|
|
1082
1205
|
if (selectedTopLevelDeps === null) {
|
|
1083
1206
|
return skills;
|
|
1084
1207
|
}
|
|
@@ -1086,6 +1209,16 @@ function topLevelSkills({
|
|
|
1086
1209
|
(skill) => selectedTopLevelDeps.has(normalizePackageName(skill.packageName))
|
|
1087
1210
|
);
|
|
1088
1211
|
}
|
|
1212
|
+
function getWorkspaceTopLevelDepsForContext(context) {
|
|
1213
|
+
const dependencySets = [
|
|
1214
|
+
context.workspace === null ? null : getWorkspaceTopLevelDeps(context.workspaceDependencyFiles),
|
|
1215
|
+
context.nodeWorkspace === null ? null : getNodeWorkspaceTopLevelDeps(context.nodeWorkspaceDependencyFiles)
|
|
1216
|
+
].filter((deps) => deps !== null);
|
|
1217
|
+
if (dependencySets.length === 0) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
return new Set(dependencySets.flatMap((deps) => [...deps]));
|
|
1221
|
+
}
|
|
1089
1222
|
function printWarnings(warnings) {
|
|
1090
1223
|
for (const warning of warnings) {
|
|
1091
1224
|
console.log(`Warning: ${warning}`);
|
|
@@ -1111,6 +1244,11 @@ function printContext(context) {
|
|
|
1111
1244
|
if (context.workspace.currentMember !== null) {
|
|
1112
1245
|
console.log(`Workspace member: ${context.workspace.currentMember}`);
|
|
1113
1246
|
}
|
|
1247
|
+
} else if (context.nodeWorkspace !== null) {
|
|
1248
|
+
console.log(`Workspace root: ${context.nodeWorkspace.root}`);
|
|
1249
|
+
if (context.nodeWorkspace.currentMember !== null) {
|
|
1250
|
+
console.log(`Workspace member: ${context.nodeWorkspace.currentMember}`);
|
|
1251
|
+
}
|
|
1114
1252
|
}
|
|
1115
1253
|
console.log(
|
|
1116
1254
|
`Target Python environment: ${context.targetEnvironment ? displayPath(context.targetEnvironment, context.projectRoot) : "not found"}`
|
|
@@ -1151,8 +1289,8 @@ function scanJsonPayload({
|
|
|
1151
1289
|
}) {
|
|
1152
1290
|
return {
|
|
1153
1291
|
project_root: context.projectRoot,
|
|
1154
|
-
workspace_root: context.workspace?.root ?? "",
|
|
1155
|
-
workspace_member: context.workspace?.currentMember ?? "",
|
|
1292
|
+
workspace_root: context.workspace?.root ?? context.nodeWorkspace?.root ?? "",
|
|
1293
|
+
workspace_member: context.workspace?.currentMember ?? context.nodeWorkspace?.currentMember ?? "",
|
|
1156
1294
|
dependency_files: context.dependencyFiles,
|
|
1157
1295
|
target_environment: context.targetEnvironment ?? "",
|
|
1158
1296
|
node_modules: context.nodeModulesDir ?? "",
|
|
@@ -1186,6 +1324,19 @@ function findCollisions(skills) {
|
|
|
1186
1324
|
[...counts.entries()].filter(([, count]) => count > 1).map(([name]) => name)
|
|
1187
1325
|
);
|
|
1188
1326
|
}
|
|
1327
|
+
function deduplicateSkills(skills) {
|
|
1328
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1329
|
+
const unique = [];
|
|
1330
|
+
for (const skill of skills) {
|
|
1331
|
+
const key = resolve5(skill.skillDir);
|
|
1332
|
+
if (seen.has(key)) {
|
|
1333
|
+
continue;
|
|
1334
|
+
}
|
|
1335
|
+
seen.add(key);
|
|
1336
|
+
unique.push(skill);
|
|
1337
|
+
}
|
|
1338
|
+
return unique;
|
|
1339
|
+
}
|
|
1189
1340
|
function filterInstallableSkills({
|
|
1190
1341
|
skills,
|
|
1191
1342
|
selectedNames,
|
|
@@ -1295,6 +1446,34 @@ async function selectSkillsInteractive(skills) {
|
|
|
1295
1446
|
}))
|
|
1296
1447
|
});
|
|
1297
1448
|
}
|
|
1449
|
+
async function selectTargetsInteractive({
|
|
1450
|
+
projectRoot,
|
|
1451
|
+
defaultTargets
|
|
1452
|
+
}) {
|
|
1453
|
+
const defaultNames = new Set(defaultTargets.map((target) => target.name));
|
|
1454
|
+
return checkbox({
|
|
1455
|
+
message: "Select installation targets (press Space to select, Enter to confirm):",
|
|
1456
|
+
choices: getAllTargetDirs(projectRoot).map((target) => ({
|
|
1457
|
+
name: displayPath(target.path, projectRoot),
|
|
1458
|
+
value: target,
|
|
1459
|
+
checked: defaultNames.has(target.name)
|
|
1460
|
+
})),
|
|
1461
|
+
validate: (selected) => selected.length > 0 || "Please select at least one installation target."
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
async function selectInstallTargets({
|
|
1465
|
+
projectRoot,
|
|
1466
|
+
includeClaude,
|
|
1467
|
+
interactive
|
|
1468
|
+
}) {
|
|
1469
|
+
if (!interactive) {
|
|
1470
|
+
return getTargetDirs(projectRoot, { includeClaude });
|
|
1471
|
+
}
|
|
1472
|
+
return selectTargetsInteractive({
|
|
1473
|
+
projectRoot,
|
|
1474
|
+
defaultTargets: getDefaultInstallTargetDirs(projectRoot)
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1298
1477
|
async function selectInstalledSkillsInteractive(statuses) {
|
|
1299
1478
|
const removable = statuses.filter((status) => status.type === "symlink");
|
|
1300
1479
|
if (removable.length === 0) {
|
|
@@ -1341,9 +1520,9 @@ function installSelected({
|
|
|
1341
1520
|
async function sync(options) {
|
|
1342
1521
|
const context = getProjectContext();
|
|
1343
1522
|
const result = scanContext(context);
|
|
1344
|
-
|
|
1523
|
+
let targets = options.yes || options.check || options.claude ? getTargetDirs(context.projectRoot, {
|
|
1345
1524
|
includeClaude: options.claude
|
|
1346
|
-
});
|
|
1525
|
+
}) : getDefaultInstallTargetDirs(context.projectRoot);
|
|
1347
1526
|
printContext(context);
|
|
1348
1527
|
console.log();
|
|
1349
1528
|
printWarnings(result.warnings);
|
|
@@ -1394,10 +1573,19 @@ async function sync(options) {
|
|
|
1394
1573
|
if (selected.length === 0 && !options.yes && selectedNames.length === 0 && !options.all) {
|
|
1395
1574
|
const newSkills = visibleStatuses.filter((status) => status.status === "new" && status.skill !== null).map((status) => status.skill);
|
|
1396
1575
|
if (newSkills.length > 0) {
|
|
1397
|
-
selected = await selectSkillsInteractive(newSkills);
|
|
1576
|
+
selected = await selectSkillsInteractive(deduplicateSkills(newSkills));
|
|
1398
1577
|
}
|
|
1399
1578
|
}
|
|
1400
1579
|
if (selected.length > 0) {
|
|
1580
|
+
targets = await selectInstallTargets({
|
|
1581
|
+
projectRoot: context.projectRoot,
|
|
1582
|
+
includeClaude: options.claude,
|
|
1583
|
+
interactive: !options.yes && !options.claude
|
|
1584
|
+
});
|
|
1585
|
+
if (targets.length === 0) {
|
|
1586
|
+
console.log("No installation targets selected.");
|
|
1587
|
+
return;
|
|
1588
|
+
}
|
|
1401
1589
|
console.log();
|
|
1402
1590
|
const installedCount = installSelected({
|
|
1403
1591
|
skills: selected,
|
|
@@ -1438,7 +1626,7 @@ function listCommand(options) {
|
|
|
1438
1626
|
skills: result.skills,
|
|
1439
1627
|
includeAll: Boolean(options.all)
|
|
1440
1628
|
});
|
|
1441
|
-
const targets =
|
|
1629
|
+
const targets = getExistingTargetDirs(context.projectRoot, {
|
|
1442
1630
|
includeClaude: options.claude
|
|
1443
1631
|
});
|
|
1444
1632
|
const statuses = installedStatuses({ targets, skills: result.skills });
|
|
@@ -1478,9 +1666,6 @@ async function installCommand(options) {
|
|
|
1478
1666
|
skills: result.skills,
|
|
1479
1667
|
includeAll: Boolean(options.all) || selectedNames.length > 0
|
|
1480
1668
|
});
|
|
1481
|
-
const targets = getTargetDirs(context.projectRoot, {
|
|
1482
|
-
includeClaude: options.claude
|
|
1483
|
-
});
|
|
1484
1669
|
printWarnings(result.warnings);
|
|
1485
1670
|
let selected = filterInstallableSkills({
|
|
1486
1671
|
skills,
|
|
@@ -1494,6 +1679,15 @@ async function installCommand(options) {
|
|
|
1494
1679
|
console.log("No skills selected.");
|
|
1495
1680
|
return;
|
|
1496
1681
|
}
|
|
1682
|
+
const targets = await selectInstallTargets({
|
|
1683
|
+
projectRoot: context.projectRoot,
|
|
1684
|
+
includeClaude: options.claude,
|
|
1685
|
+
interactive: !options.yes && !options.claude
|
|
1686
|
+
});
|
|
1687
|
+
if (targets.length === 0) {
|
|
1688
|
+
console.log("No installation targets selected.");
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1497
1691
|
const installedCount = installSelected({
|
|
1498
1692
|
skills: selected,
|
|
1499
1693
|
targets,
|
|
@@ -1506,7 +1700,7 @@ async function installCommand(options) {
|
|
|
1506
1700
|
async function removeCommand(skillNames, options) {
|
|
1507
1701
|
const context = getProjectContext();
|
|
1508
1702
|
const result = scanContext(context);
|
|
1509
|
-
const targets =
|
|
1703
|
+
const targets = getExistingTargetDirs(context.projectRoot, {
|
|
1510
1704
|
includeClaude: options.claude
|
|
1511
1705
|
});
|
|
1512
1706
|
const statuses = installedStatuses({ targets, skills: result.skills });
|
package/ts/dist/deps.cjs
CHANGED
|
@@ -21,6 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var deps_exports = {};
|
|
22
22
|
__export(deps_exports, {
|
|
23
23
|
getNodeTopLevelDeps: () => getNodeTopLevelDeps,
|
|
24
|
+
getNodeTopLevelDepsFromFiles: () => getNodeTopLevelDepsFromFiles,
|
|
25
|
+
getNodeWorkspaceTopLevelDeps: () => getNodeWorkspaceTopLevelDeps,
|
|
24
26
|
getPythonTopLevelDeps: () => getPythonTopLevelDeps,
|
|
25
27
|
getPythonTopLevelDepsFromFiles: () => getPythonTopLevelDepsFromFiles,
|
|
26
28
|
getTopLevelDeps: () => getTopLevelDeps,
|
|
@@ -98,6 +100,28 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
98
100
|
if (!(0, import_node_fs2.existsSync)(packageJson)) {
|
|
99
101
|
return null;
|
|
100
102
|
}
|
|
103
|
+
return getNodeTopLevelDepsFromFiles([packageJson]);
|
|
104
|
+
}
|
|
105
|
+
function getNodeTopLevelDepsFromFiles(packageJsonFiles) {
|
|
106
|
+
if (packageJsonFiles.length === 0) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const deps = /* @__PURE__ */ new Set();
|
|
110
|
+
let found = false;
|
|
111
|
+
for (const packageJson of packageJsonFiles) {
|
|
112
|
+
if (!(0, import_node_fs2.existsSync)(packageJson)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const data = readPackageJson(packageJson);
|
|
116
|
+
if (data === null) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
found = true;
|
|
120
|
+
extractNodeTopLevelDeps(data, deps);
|
|
121
|
+
}
|
|
122
|
+
return found ? deps : null;
|
|
123
|
+
}
|
|
124
|
+
function readPackageJson(packageJson) {
|
|
101
125
|
let data;
|
|
102
126
|
try {
|
|
103
127
|
data = JSON.parse((0, import_node_fs2.readFileSync)(packageJson, "utf8"));
|
|
@@ -105,9 +129,11 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
105
129
|
return null;
|
|
106
130
|
}
|
|
107
131
|
if (!isRecord(data)) {
|
|
108
|
-
return
|
|
132
|
+
return {};
|
|
109
133
|
}
|
|
110
|
-
|
|
134
|
+
return data;
|
|
135
|
+
}
|
|
136
|
+
function extractNodeTopLevelDeps(data, deps) {
|
|
111
137
|
for (const field of [
|
|
112
138
|
"dependencies",
|
|
113
139
|
"devDependencies",
|
|
@@ -122,7 +148,6 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
122
148
|
deps.add(normalizePackageName(packageName));
|
|
123
149
|
}
|
|
124
150
|
}
|
|
125
|
-
return deps;
|
|
126
151
|
}
|
|
127
152
|
function getTopLevelDeps(projectRoot) {
|
|
128
153
|
const dependencySets = [
|
|
@@ -137,6 +162,9 @@ function getTopLevelDeps(projectRoot) {
|
|
|
137
162
|
function getWorkspaceTopLevelDeps(pyprojects) {
|
|
138
163
|
return getPythonTopLevelDepsFromFiles(pyprojects);
|
|
139
164
|
}
|
|
165
|
+
function getNodeWorkspaceTopLevelDeps(packageJsonFiles) {
|
|
166
|
+
return getNodeTopLevelDepsFromFiles(packageJsonFiles);
|
|
167
|
+
}
|
|
140
168
|
function extractDepsFromSpecs(depSpecs, deps) {
|
|
141
169
|
for (const depSpec of depSpecs) {
|
|
142
170
|
if (typeof depSpec !== "string") {
|
|
@@ -184,6 +212,8 @@ var testing = {
|
|
|
184
212
|
// Annotate the CommonJS export names for ESM import in node:
|
|
185
213
|
0 && (module.exports = {
|
|
186
214
|
getNodeTopLevelDeps,
|
|
215
|
+
getNodeTopLevelDepsFromFiles,
|
|
216
|
+
getNodeWorkspaceTopLevelDeps,
|
|
187
217
|
getPythonTopLevelDeps,
|
|
188
218
|
getPythonTopLevelDepsFromFiles,
|
|
189
219
|
getTopLevelDeps,
|
package/ts/dist/deps.d.cts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
declare function getPythonTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
2
2
|
declare function getPythonTopLevelDepsFromFiles(pyprojects: string[]): Set<string> | null;
|
|
3
3
|
declare function getNodeTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
4
|
+
declare function getNodeTopLevelDepsFromFiles(packageJsonFiles: string[]): Set<string> | null;
|
|
4
5
|
declare function getTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
5
6
|
declare function getWorkspaceTopLevelDeps(pyprojects: string[]): Set<string> | null;
|
|
7
|
+
declare function getNodeWorkspaceTopLevelDeps(packageJsonFiles: string[]): Set<string> | null;
|
|
6
8
|
declare function extractDepsFromSpecs(depSpecs: unknown[], deps: Set<string>): void;
|
|
7
9
|
declare function extractDepsFromDependencyGroup(groupName: unknown, dependencyGroups: Record<string, unknown>, deps: Set<string>, visited: Set<unknown>): void;
|
|
8
10
|
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
@@ -12,4 +14,4 @@ declare const testing: {
|
|
|
12
14
|
isRecord: typeof isRecord;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
export { getNodeTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };
|
|
17
|
+
export { getNodeTopLevelDeps, getNodeTopLevelDepsFromFiles, getNodeWorkspaceTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };
|
package/ts/dist/deps.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
declare function getPythonTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
2
2
|
declare function getPythonTopLevelDepsFromFiles(pyprojects: string[]): Set<string> | null;
|
|
3
3
|
declare function getNodeTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
4
|
+
declare function getNodeTopLevelDepsFromFiles(packageJsonFiles: string[]): Set<string> | null;
|
|
4
5
|
declare function getTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
5
6
|
declare function getWorkspaceTopLevelDeps(pyprojects: string[]): Set<string> | null;
|
|
7
|
+
declare function getNodeWorkspaceTopLevelDeps(packageJsonFiles: string[]): Set<string> | null;
|
|
6
8
|
declare function extractDepsFromSpecs(depSpecs: unknown[], deps: Set<string>): void;
|
|
7
9
|
declare function extractDepsFromDependencyGroup(groupName: unknown, dependencyGroups: Record<string, unknown>, deps: Set<string>, visited: Set<unknown>): void;
|
|
8
10
|
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
@@ -12,4 +14,4 @@ declare const testing: {
|
|
|
12
14
|
isRecord: typeof isRecord;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
export { getNodeTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };
|
|
17
|
+
export { getNodeTopLevelDeps, getNodeTopLevelDepsFromFiles, getNodeWorkspaceTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };
|
package/ts/dist/deps.js
CHANGED
|
@@ -62,6 +62,28 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
62
62
|
if (!existsSync(packageJson)) {
|
|
63
63
|
return null;
|
|
64
64
|
}
|
|
65
|
+
return getNodeTopLevelDepsFromFiles([packageJson]);
|
|
66
|
+
}
|
|
67
|
+
function getNodeTopLevelDepsFromFiles(packageJsonFiles) {
|
|
68
|
+
if (packageJsonFiles.length === 0) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const deps = /* @__PURE__ */ new Set();
|
|
72
|
+
let found = false;
|
|
73
|
+
for (const packageJson of packageJsonFiles) {
|
|
74
|
+
if (!existsSync(packageJson)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const data = readPackageJson(packageJson);
|
|
78
|
+
if (data === null) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
found = true;
|
|
82
|
+
extractNodeTopLevelDeps(data, deps);
|
|
83
|
+
}
|
|
84
|
+
return found ? deps : null;
|
|
85
|
+
}
|
|
86
|
+
function readPackageJson(packageJson) {
|
|
65
87
|
let data;
|
|
66
88
|
try {
|
|
67
89
|
data = JSON.parse(readFileSync(packageJson, "utf8"));
|
|
@@ -69,9 +91,11 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
69
91
|
return null;
|
|
70
92
|
}
|
|
71
93
|
if (!isRecord(data)) {
|
|
72
|
-
return
|
|
94
|
+
return {};
|
|
73
95
|
}
|
|
74
|
-
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
98
|
+
function extractNodeTopLevelDeps(data, deps) {
|
|
75
99
|
for (const field of [
|
|
76
100
|
"dependencies",
|
|
77
101
|
"devDependencies",
|
|
@@ -86,7 +110,6 @@ function getNodeTopLevelDeps(projectRoot) {
|
|
|
86
110
|
deps.add(normalizePackageName(packageName));
|
|
87
111
|
}
|
|
88
112
|
}
|
|
89
|
-
return deps;
|
|
90
113
|
}
|
|
91
114
|
function getTopLevelDeps(projectRoot) {
|
|
92
115
|
const dependencySets = [
|
|
@@ -101,6 +124,9 @@ function getTopLevelDeps(projectRoot) {
|
|
|
101
124
|
function getWorkspaceTopLevelDeps(pyprojects) {
|
|
102
125
|
return getPythonTopLevelDepsFromFiles(pyprojects);
|
|
103
126
|
}
|
|
127
|
+
function getNodeWorkspaceTopLevelDeps(packageJsonFiles) {
|
|
128
|
+
return getNodeTopLevelDepsFromFiles(packageJsonFiles);
|
|
129
|
+
}
|
|
104
130
|
function extractDepsFromSpecs(depSpecs, deps) {
|
|
105
131
|
for (const depSpec of depSpecs) {
|
|
106
132
|
if (typeof depSpec !== "string") {
|
|
@@ -147,6 +173,8 @@ var testing = {
|
|
|
147
173
|
};
|
|
148
174
|
export {
|
|
149
175
|
getNodeTopLevelDeps,
|
|
176
|
+
getNodeTopLevelDepsFromFiles,
|
|
177
|
+
getNodeWorkspaceTopLevelDeps,
|
|
150
178
|
getPythonTopLevelDeps,
|
|
151
179
|
getPythonTopLevelDepsFromFiles,
|
|
152
180
|
getTopLevelDeps,
|
package/ts/dist/installer.cjs
CHANGED
|
@@ -23,6 +23,9 @@ __export(installer_exports, {
|
|
|
23
23
|
CLAUDE_SKILLS_DIR: () => CLAUDE_SKILLS_DIR,
|
|
24
24
|
InstallError: () => InstallError,
|
|
25
25
|
UNIVERSAL_SKILLS_DIR: () => UNIVERSAL_SKILLS_DIR,
|
|
26
|
+
getAllTargetDirs: () => getAllTargetDirs,
|
|
27
|
+
getDefaultInstallTargetDirs: () => getDefaultInstallTargetDirs,
|
|
28
|
+
getExistingTargetDirs: () => getExistingTargetDirs,
|
|
26
29
|
getTargetDirs: () => getTargetDirs,
|
|
27
30
|
installSkill: () => installSkill,
|
|
28
31
|
listInstalledSkills: () => listInstalledSkills,
|
|
@@ -52,6 +55,26 @@ function getTargetDirs(projectRoot, options = {}) {
|
|
|
52
55
|
}
|
|
53
56
|
return targets;
|
|
54
57
|
}
|
|
58
|
+
function getAllTargetDirs(projectRoot) {
|
|
59
|
+
return getTargetDirs(projectRoot, { includeClaude: true });
|
|
60
|
+
}
|
|
61
|
+
function getDefaultInstallTargetDirs(projectRoot) {
|
|
62
|
+
const [universal, claude] = getAllTargetDirs(projectRoot);
|
|
63
|
+
const selected = [];
|
|
64
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(projectRoot, ".agents"))) {
|
|
65
|
+
selected.push(universal);
|
|
66
|
+
}
|
|
67
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(projectRoot, ".claude"))) {
|
|
68
|
+
selected.push(claude);
|
|
69
|
+
}
|
|
70
|
+
return selected.length > 0 ? selected : [universal];
|
|
71
|
+
}
|
|
72
|
+
function getExistingTargetDirs(projectRoot, options = {}) {
|
|
73
|
+
if (options.includeClaude) {
|
|
74
|
+
return getTargetDirs(projectRoot, { includeClaude: true });
|
|
75
|
+
}
|
|
76
|
+
return getAllTargetDirs(projectRoot).filter((target) => isDirectory(target.path));
|
|
77
|
+
}
|
|
55
78
|
function installSkill(skill, targetDir, options = {}) {
|
|
56
79
|
const dest = (0, import_node_path.join)(targetDir, skill.name);
|
|
57
80
|
const source = (0, import_node_path.resolve)(skill.skillDir);
|
|
@@ -137,6 +160,9 @@ var testing = {
|
|
|
137
160
|
CLAUDE_SKILLS_DIR,
|
|
138
161
|
InstallError,
|
|
139
162
|
UNIVERSAL_SKILLS_DIR,
|
|
163
|
+
getAllTargetDirs,
|
|
164
|
+
getDefaultInstallTargetDirs,
|
|
165
|
+
getExistingTargetDirs,
|
|
140
166
|
getTargetDirs,
|
|
141
167
|
installSkill,
|
|
142
168
|
listInstalledSkills,
|
package/ts/dist/installer.d.cts
CHANGED
|
@@ -19,6 +19,11 @@ declare class InstallError extends Error {
|
|
|
19
19
|
declare function getTargetDirs(projectRoot: string, options?: {
|
|
20
20
|
includeClaude?: boolean;
|
|
21
21
|
}): InstallTarget[];
|
|
22
|
+
declare function getAllTargetDirs(projectRoot: string): InstallTarget[];
|
|
23
|
+
declare function getDefaultInstallTargetDirs(projectRoot: string): InstallTarget[];
|
|
24
|
+
declare function getExistingTargetDirs(projectRoot: string, options?: {
|
|
25
|
+
includeClaude?: boolean;
|
|
26
|
+
}): InstallTarget[];
|
|
22
27
|
declare function installSkill(skill: Skill, targetDir: string, options?: {
|
|
23
28
|
copy?: boolean;
|
|
24
29
|
}): string;
|
|
@@ -38,4 +43,4 @@ declare const testing: {
|
|
|
38
43
|
resolveSymlink: typeof resolveSymlink;
|
|
39
44
|
};
|
|
40
45
|
|
|
41
|
-
export { CLAUDE_SKILLS_DIR, InstallError, type InstallTarget, type InstalledSkill, UNIVERSAL_SKILLS_DIR, getTargetDirs, installSkill, listInstalledSkills, testing, uninstallSkill };
|
|
46
|
+
export { CLAUDE_SKILLS_DIR, InstallError, type InstallTarget, type InstalledSkill, UNIVERSAL_SKILLS_DIR, getAllTargetDirs, getDefaultInstallTargetDirs, getExistingTargetDirs, getTargetDirs, installSkill, listInstalledSkills, testing, uninstallSkill };
|
package/ts/dist/installer.d.ts
CHANGED
|
@@ -19,6 +19,11 @@ declare class InstallError extends Error {
|
|
|
19
19
|
declare function getTargetDirs(projectRoot: string, options?: {
|
|
20
20
|
includeClaude?: boolean;
|
|
21
21
|
}): InstallTarget[];
|
|
22
|
+
declare function getAllTargetDirs(projectRoot: string): InstallTarget[];
|
|
23
|
+
declare function getDefaultInstallTargetDirs(projectRoot: string): InstallTarget[];
|
|
24
|
+
declare function getExistingTargetDirs(projectRoot: string, options?: {
|
|
25
|
+
includeClaude?: boolean;
|
|
26
|
+
}): InstallTarget[];
|
|
22
27
|
declare function installSkill(skill: Skill, targetDir: string, options?: {
|
|
23
28
|
copy?: boolean;
|
|
24
29
|
}): string;
|
|
@@ -38,4 +43,4 @@ declare const testing: {
|
|
|
38
43
|
resolveSymlink: typeof resolveSymlink;
|
|
39
44
|
};
|
|
40
45
|
|
|
41
|
-
export { CLAUDE_SKILLS_DIR, InstallError, type InstallTarget, type InstalledSkill, UNIVERSAL_SKILLS_DIR, getTargetDirs, installSkill, listInstalledSkills, testing, uninstallSkill };
|
|
46
|
+
export { CLAUDE_SKILLS_DIR, InstallError, type InstallTarget, type InstalledSkill, UNIVERSAL_SKILLS_DIR, getAllTargetDirs, getDefaultInstallTargetDirs, getExistingTargetDirs, getTargetDirs, installSkill, listInstalledSkills, testing, uninstallSkill };
|
package/ts/dist/installer.js
CHANGED
|
@@ -31,6 +31,26 @@ function getTargetDirs(projectRoot, options = {}) {
|
|
|
31
31
|
}
|
|
32
32
|
return targets;
|
|
33
33
|
}
|
|
34
|
+
function getAllTargetDirs(projectRoot) {
|
|
35
|
+
return getTargetDirs(projectRoot, { includeClaude: true });
|
|
36
|
+
}
|
|
37
|
+
function getDefaultInstallTargetDirs(projectRoot) {
|
|
38
|
+
const [universal, claude] = getAllTargetDirs(projectRoot);
|
|
39
|
+
const selected = [];
|
|
40
|
+
if (existsSync(join(projectRoot, ".agents"))) {
|
|
41
|
+
selected.push(universal);
|
|
42
|
+
}
|
|
43
|
+
if (existsSync(join(projectRoot, ".claude"))) {
|
|
44
|
+
selected.push(claude);
|
|
45
|
+
}
|
|
46
|
+
return selected.length > 0 ? selected : [universal];
|
|
47
|
+
}
|
|
48
|
+
function getExistingTargetDirs(projectRoot, options = {}) {
|
|
49
|
+
if (options.includeClaude) {
|
|
50
|
+
return getTargetDirs(projectRoot, { includeClaude: true });
|
|
51
|
+
}
|
|
52
|
+
return getAllTargetDirs(projectRoot).filter((target) => isDirectory(target.path));
|
|
53
|
+
}
|
|
34
54
|
function installSkill(skill, targetDir, options = {}) {
|
|
35
55
|
const dest = join(targetDir, skill.name);
|
|
36
56
|
const source = resolve(skill.skillDir);
|
|
@@ -115,6 +135,9 @@ export {
|
|
|
115
135
|
CLAUDE_SKILLS_DIR,
|
|
116
136
|
InstallError,
|
|
117
137
|
UNIVERSAL_SKILLS_DIR,
|
|
138
|
+
getAllTargetDirs,
|
|
139
|
+
getDefaultInstallTargetDirs,
|
|
140
|
+
getExistingTargetDirs,
|
|
118
141
|
getTargetDirs,
|
|
119
142
|
installSkill,
|
|
120
143
|
listInstalledSkills,
|
package/ts/dist/python-env.cjs
CHANGED
|
@@ -53,6 +53,26 @@ function findUvWorkspace(cwd) {
|
|
|
53
53
|
}
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
|
+
function findNodeWorkspace(cwd) {
|
|
57
|
+
for (const directory of ancestors(cwd)) {
|
|
58
|
+
const packageJson = `${directory}/package.json`;
|
|
59
|
+
if (!(0, import_node_fs.existsSync)(packageJson)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const data = readPackageJson(packageJson);
|
|
63
|
+
const memberGlobs = getNodeWorkspaceGlobs(data);
|
|
64
|
+
if (memberGlobs === null) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const members = findNodeWorkspaceMembers(directory, memberGlobs);
|
|
68
|
+
return {
|
|
69
|
+
root: directory,
|
|
70
|
+
members,
|
|
71
|
+
currentMember: findCurrentMember(cwd, members)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
56
76
|
function readPyproject(path) {
|
|
57
77
|
try {
|
|
58
78
|
const data = (0, import_smol_toml.parse)((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
@@ -61,6 +81,14 @@ function readPyproject(path) {
|
|
|
61
81
|
return {};
|
|
62
82
|
}
|
|
63
83
|
}
|
|
84
|
+
function readPackageJson(path) {
|
|
85
|
+
try {
|
|
86
|
+
const data = JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
87
|
+
return isRecord(data) ? data : {};
|
|
88
|
+
} catch {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
64
92
|
function hasUvWorkspace(data) {
|
|
65
93
|
const tool = data["tool"];
|
|
66
94
|
if (!isRecord(tool)) {
|
|
@@ -97,6 +125,36 @@ function findWorkspaceMembers(root, data) {
|
|
|
97
125
|
}
|
|
98
126
|
return [...members].sort();
|
|
99
127
|
}
|
|
128
|
+
function getNodeWorkspaceGlobs(data) {
|
|
129
|
+
const workspaces = data["workspaces"];
|
|
130
|
+
if (Array.isArray(workspaces)) {
|
|
131
|
+
return workspaces.filter((value) => typeof value === "string");
|
|
132
|
+
}
|
|
133
|
+
if (isRecord(workspaces)) {
|
|
134
|
+
const packages = workspaces["packages"];
|
|
135
|
+
if (Array.isArray(packages)) {
|
|
136
|
+
return packages.filter((value) => typeof value === "string");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
function findNodeWorkspaceMembers(root, memberGlobs) {
|
|
142
|
+
const includes = memberGlobs.filter((pattern) => !pattern.startsWith("!"));
|
|
143
|
+
const excludes = memberGlobs.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1));
|
|
144
|
+
const members = /* @__PURE__ */ new Set();
|
|
145
|
+
for (const memberGlob of includes) {
|
|
146
|
+
for (const member of expandMemberGlob(root, memberGlob)) {
|
|
147
|
+
const relativePath = (0, import_node_path.relative)(root, member).split(import_node_path.sep).join("/");
|
|
148
|
+
if (isExcluded(relativePath, excludes)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (isFile(`${member}/package.json`)) {
|
|
152
|
+
members.add((0, import_node_path.resolve)(member));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return [...members].sort();
|
|
157
|
+
}
|
|
100
158
|
function getWorkspaceTable(data) {
|
|
101
159
|
const tool = data["tool"];
|
|
102
160
|
if (!isRecord(tool)) {
|
|
@@ -204,6 +262,10 @@ function findProjectRoot(cwd) {
|
|
|
204
262
|
if (workspace !== null) {
|
|
205
263
|
return workspace.root;
|
|
206
264
|
}
|
|
265
|
+
const nodeWorkspace = findNodeWorkspace(cwd);
|
|
266
|
+
if (nodeWorkspace !== null) {
|
|
267
|
+
return nodeWorkspace.root;
|
|
268
|
+
}
|
|
207
269
|
for (const directory of ancestors2(cwd)) {
|
|
208
270
|
if (isFile2((0, import_node_path2.join)(directory, "pyproject.toml")) || isFile2((0, import_node_path2.join)(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2((0, import_node_path2.join)(directory, "package.json")) || isDirectory2((0, import_node_path2.join)(directory, "node_modules"))) {
|
|
209
271
|
return directory;
|
package/ts/dist/python-env.js
CHANGED
|
@@ -25,6 +25,26 @@ function findUvWorkspace(cwd) {
|
|
|
25
25
|
}
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
|
+
function findNodeWorkspace(cwd) {
|
|
29
|
+
for (const directory of ancestors(cwd)) {
|
|
30
|
+
const packageJson = `${directory}/package.json`;
|
|
31
|
+
if (!existsSync(packageJson)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const data = readPackageJson(packageJson);
|
|
35
|
+
const memberGlobs = getNodeWorkspaceGlobs(data);
|
|
36
|
+
if (memberGlobs === null) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const members = findNodeWorkspaceMembers(directory, memberGlobs);
|
|
40
|
+
return {
|
|
41
|
+
root: directory,
|
|
42
|
+
members,
|
|
43
|
+
currentMember: findCurrentMember(cwd, members)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
28
48
|
function readPyproject(path) {
|
|
29
49
|
try {
|
|
30
50
|
const data = parse(readFileSync(path, "utf8"));
|
|
@@ -33,6 +53,14 @@ function readPyproject(path) {
|
|
|
33
53
|
return {};
|
|
34
54
|
}
|
|
35
55
|
}
|
|
56
|
+
function readPackageJson(path) {
|
|
57
|
+
try {
|
|
58
|
+
const data = JSON.parse(readFileSync(path, "utf8"));
|
|
59
|
+
return isRecord(data) ? data : {};
|
|
60
|
+
} catch {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
36
64
|
function hasUvWorkspace(data) {
|
|
37
65
|
const tool = data["tool"];
|
|
38
66
|
if (!isRecord(tool)) {
|
|
@@ -69,6 +97,36 @@ function findWorkspaceMembers(root, data) {
|
|
|
69
97
|
}
|
|
70
98
|
return [...members].sort();
|
|
71
99
|
}
|
|
100
|
+
function getNodeWorkspaceGlobs(data) {
|
|
101
|
+
const workspaces = data["workspaces"];
|
|
102
|
+
if (Array.isArray(workspaces)) {
|
|
103
|
+
return workspaces.filter((value) => typeof value === "string");
|
|
104
|
+
}
|
|
105
|
+
if (isRecord(workspaces)) {
|
|
106
|
+
const packages = workspaces["packages"];
|
|
107
|
+
if (Array.isArray(packages)) {
|
|
108
|
+
return packages.filter((value) => typeof value === "string");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
function findNodeWorkspaceMembers(root, memberGlobs) {
|
|
114
|
+
const includes = memberGlobs.filter((pattern) => !pattern.startsWith("!"));
|
|
115
|
+
const excludes = memberGlobs.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1));
|
|
116
|
+
const members = /* @__PURE__ */ new Set();
|
|
117
|
+
for (const memberGlob of includes) {
|
|
118
|
+
for (const member of expandMemberGlob(root, memberGlob)) {
|
|
119
|
+
const relativePath = relative(root, member).split(sep).join("/");
|
|
120
|
+
if (isExcluded(relativePath, excludes)) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (isFile(`${member}/package.json`)) {
|
|
124
|
+
members.add(resolve(member));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return [...members].sort();
|
|
129
|
+
}
|
|
72
130
|
function getWorkspaceTable(data) {
|
|
73
131
|
const tool = data["tool"];
|
|
74
132
|
if (!isRecord(tool)) {
|
|
@@ -176,6 +234,10 @@ function findProjectRoot(cwd) {
|
|
|
176
234
|
if (workspace !== null) {
|
|
177
235
|
return workspace.root;
|
|
178
236
|
}
|
|
237
|
+
const nodeWorkspace = findNodeWorkspace(cwd);
|
|
238
|
+
if (nodeWorkspace !== null) {
|
|
239
|
+
return nodeWorkspace.root;
|
|
240
|
+
}
|
|
179
241
|
for (const directory of ancestors2(cwd)) {
|
|
180
242
|
if (isFile2(join(directory, "pyproject.toml")) || isFile2(join(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2(join(directory, "package.json")) || isDirectory2(join(directory, "node_modules"))) {
|
|
181
243
|
return directory;
|