library-skills 0.0.7 → 0.0.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "library-skills",
3
- "version": "0.0.7",
3
+ "version": "0.0.10",
4
4
  "description": "Library Skills, AI Agents using libraries, as intended, always up to date.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -100,6 +100,9 @@ function iterNodePackageRoots(nodeModules) {
100
100
  if (!isDirectory(fullPath)) {
101
101
  continue;
102
102
  }
103
+ if (entry.startsWith(".")) {
104
+ continue;
105
+ }
103
106
  if (entry.startsWith("@")) {
104
107
  for (const scopedEntry of readdirSync(fullPath).sort()) {
105
108
  const scopedPath = join(fullPath, scopedEntry);
package/ts/dist/cli.js CHANGED
@@ -3,8 +3,8 @@
3
3
  // ts/src/cli.ts
4
4
  import checkbox from "@inquirer/checkbox";
5
5
  import { Command } from "commander";
6
- import { realpathSync as realpathSync2, statSync as statSync4 } from "fs";
7
- import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve4 } from "path";
6
+ import { realpathSync as realpathSync2, statSync as statSync5 } from "fs";
7
+ import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve5 } from "path";
8
8
  import { fileURLToPath as fileURLToPath2 } from "url";
9
9
 
10
10
  // ts/src/deps.ts
@@ -114,6 +114,9 @@ function iterNodePackageRoots(nodeModules) {
114
114
  if (!isDirectory(fullPath)) {
115
115
  continue;
116
116
  }
117
+ if (entry.startsWith(".")) {
118
+ continue;
119
+ }
117
120
  if (entry.startsWith("@")) {
118
121
  for (const scopedEntry of readdirSync(fullPath).sort()) {
119
122
  const scopedPath = join(fullPath, scopedEntry);
@@ -468,13 +471,30 @@ function getPythonTopLevelDeps(projectRoot) {
468
471
  if (!existsSync2(pyproject)) {
469
472
  return null;
470
473
  }
471
- let data;
472
- try {
473
- data = parse2(readFileSync2(pyproject, "utf8"));
474
- } catch {
474
+ return getPythonTopLevelDepsFromFiles([pyproject]);
475
+ }
476
+ function getPythonTopLevelDepsFromFiles(pyprojects) {
477
+ if (pyprojects.length === 0) {
475
478
  return null;
476
479
  }
477
480
  const deps = /* @__PURE__ */ new Set();
481
+ let found = false;
482
+ for (const pyproject of pyprojects) {
483
+ if (!existsSync2(pyproject)) {
484
+ continue;
485
+ }
486
+ let data;
487
+ try {
488
+ data = parse2(readFileSync2(pyproject, "utf8"));
489
+ } catch {
490
+ return null;
491
+ }
492
+ found = true;
493
+ extractPythonTopLevelDeps(data, deps);
494
+ }
495
+ return found ? deps : null;
496
+ }
497
+ function extractPythonTopLevelDeps(data, deps) {
478
498
  const project = data["project"];
479
499
  if (isRecord2(project)) {
480
500
  const dependencies = project["dependencies"];
@@ -496,7 +516,6 @@ function getPythonTopLevelDeps(projectRoot) {
496
516
  extractDepsFromDependencyGroup(groupName, dependencyGroups, deps, /* @__PURE__ */ new Set());
497
517
  }
498
518
  }
499
- return deps;
500
519
  }
501
520
  function getNodeTopLevelDeps(projectRoot) {
502
521
  const packageJson = join2(projectRoot, "package.json");
@@ -539,12 +558,15 @@ function getTopLevelDeps(projectRoot) {
539
558
  }
540
559
  return new Set(dependencySets.flatMap((deps) => [...deps]));
541
560
  }
561
+ function getWorkspaceTopLevelDeps(pyprojects) {
562
+ return getPythonTopLevelDepsFromFiles(pyprojects);
563
+ }
542
564
  function extractDepsFromSpecs(depSpecs, deps) {
543
565
  for (const depSpec of depSpecs) {
544
566
  if (typeof depSpec !== "string") {
545
567
  continue;
546
568
  }
547
- const packageName = depSpec.split(/[>=<![\];,\s]/)[0]?.trim();
569
+ const packageName = depSpec.split(/[~>=<![\];,\s]/)[0]?.trim();
548
570
  if (packageName && !packageName.startsWith("#")) {
549
571
  deps.add(normalizePackageName(packageName));
550
572
  }
@@ -688,17 +710,201 @@ function isDirectory2(path) {
688
710
  }
689
711
 
690
712
  // ts/src/python-env.ts
691
- import { readFileSync as readFileSync3, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
692
- import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve3, sep } from "path";
693
- function findProjectRoot(cwd) {
713
+ import { readFileSync as readFileSync4, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
714
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve4, sep as sep2 } from "path";
715
+
716
+ // ts/src/workspace.ts
717
+ import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
718
+ import { relative as relative3, resolve as resolve3, sep } from "path";
719
+ import { parse as parse3 } from "smol-toml";
720
+ function findUvWorkspace(cwd) {
694
721
  for (const directory of ancestors(cwd)) {
695
- if (isFile(join4(directory, "pyproject.toml")) || isFile(join4(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile(join4(directory, "package.json")) || isDirectory3(join4(directory, "node_modules"))) {
722
+ const pyproject = `${directory}/pyproject.toml`;
723
+ if (!existsSync4(pyproject)) {
724
+ continue;
725
+ }
726
+ const data = readPyproject(pyproject);
727
+ if (!hasUvWorkspace(data)) {
728
+ continue;
729
+ }
730
+ const members = findWorkspaceMembers(directory, data);
731
+ return {
732
+ root: directory,
733
+ members,
734
+ currentMember: findCurrentMember(cwd, members)
735
+ };
736
+ }
737
+ return null;
738
+ }
739
+ function workspaceDependencyFiles(workspace) {
740
+ if (workspace.currentMember !== null) {
741
+ return [`${workspace.currentMember}/pyproject.toml`];
742
+ }
743
+ return [
744
+ `${workspace.root}/pyproject.toml`,
745
+ ...workspace.members.map((member) => `${member}/pyproject.toml`)
746
+ ].filter((path) => existsSync4(path));
747
+ }
748
+ function readPyproject(path) {
749
+ try {
750
+ const data = parse3(readFileSync3(path, "utf8"));
751
+ return isRecord3(data) ? data : {};
752
+ } catch {
753
+ return {};
754
+ }
755
+ }
756
+ function hasUvWorkspace(data) {
757
+ const tool = data["tool"];
758
+ if (!isRecord3(tool)) {
759
+ return false;
760
+ }
761
+ const uv = tool["uv"];
762
+ if (!isRecord3(uv)) {
763
+ return false;
764
+ }
765
+ return isRecord3(uv["workspace"]);
766
+ }
767
+ function findWorkspaceMembers(root, data) {
768
+ const workspace = getWorkspaceTable(data);
769
+ if (workspace === null || !Array.isArray(workspace["members"])) {
770
+ return [];
771
+ }
772
+ const excludes = Array.isArray(workspace["exclude"]) ? workspace["exclude"].filter(
773
+ (value) => typeof value === "string"
774
+ ) : [];
775
+ const members = /* @__PURE__ */ new Set();
776
+ for (const memberGlob of workspace["members"]) {
777
+ if (typeof memberGlob !== "string") {
778
+ continue;
779
+ }
780
+ for (const member of expandMemberGlob(root, memberGlob)) {
781
+ const relativePath = relative3(root, member).split(sep).join("/");
782
+ if (isExcluded(relativePath, excludes)) {
783
+ continue;
784
+ }
785
+ if (isFile(`${member}/pyproject.toml`)) {
786
+ members.add(resolve3(member));
787
+ }
788
+ }
789
+ }
790
+ return [...members].sort();
791
+ }
792
+ function getWorkspaceTable(data) {
793
+ const tool = data["tool"];
794
+ if (!isRecord3(tool)) {
795
+ return null;
796
+ }
797
+ const uv = tool["uv"];
798
+ if (!isRecord3(uv)) {
799
+ return null;
800
+ }
801
+ const workspace = uv["workspace"];
802
+ return isRecord3(workspace) ? workspace : null;
803
+ }
804
+ function expandMemberGlob(root, pattern) {
805
+ const parts = pattern.split("/");
806
+ const results = [];
807
+ walkGlob(root, parts, results);
808
+ return results;
809
+ }
810
+ function walkGlob(directory, parts, results) {
811
+ if (parts.length === 0) {
812
+ if (isDirectory3(directory)) {
813
+ results.push(directory);
814
+ }
815
+ return;
816
+ }
817
+ const [part, ...rest] = parts;
818
+ if (part === "*") {
819
+ for (const entry of readDirSafe(directory)) {
820
+ const child = `${directory}/${entry}`;
821
+ if (isDirectory3(child)) {
822
+ walkGlob(child, rest, results);
823
+ }
824
+ }
825
+ return;
826
+ }
827
+ walkGlob(`${directory}/${part}`, rest, results);
828
+ }
829
+ function isExcluded(relativePath, excludes) {
830
+ return excludes.some(
831
+ (pattern) => globMatches(relativePath, pattern.replace(/\/$/, ""))
832
+ );
833
+ }
834
+ function globMatches(value, pattern) {
835
+ if (pattern === value) {
836
+ return true;
837
+ }
838
+ const regex = new RegExp(`^${pattern.split("*").map(escapeRegex).join(".*")}$`);
839
+ return regex.test(value);
840
+ }
841
+ function findCurrentMember(cwd, members) {
842
+ const resolvedCwd = resolve3(cwd);
843
+ const matches = members.filter((member) => isRelativeTo2(resolvedCwd, member));
844
+ if (matches.length === 0) {
845
+ return null;
846
+ }
847
+ return matches.sort((left, right) => right.length - left.length)[0] ?? null;
848
+ }
849
+ function ancestors(start) {
850
+ const result = [];
851
+ let directory = resolve3(start);
852
+ while (true) {
853
+ result.push(directory);
854
+ const parent = resolve3(directory, "..");
855
+ if (parent === directory) {
856
+ break;
857
+ }
858
+ directory = parent;
859
+ }
860
+ return result;
861
+ }
862
+ function isRelativeTo2(path, parent) {
863
+ const normalizedPath = resolve3(path);
864
+ const normalizedParent = resolve3(parent);
865
+ return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep}`);
866
+ }
867
+ function isRecord3(value) {
868
+ return typeof value === "object" && value !== null && !Array.isArray(value);
869
+ }
870
+ function isFile(path) {
871
+ try {
872
+ return statSync3(path).isFile();
873
+ } catch {
874
+ return false;
875
+ }
876
+ }
877
+ function isDirectory3(path) {
878
+ try {
879
+ return statSync3(path).isDirectory();
880
+ } catch {
881
+ return false;
882
+ }
883
+ }
884
+ function readDirSafe(path) {
885
+ try {
886
+ return isDirectory3(path) ? readdirSync3(path) : [];
887
+ } catch {
888
+ return [];
889
+ }
890
+ }
891
+ var escapeRegex = (value) => value.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
892
+
893
+ // ts/src/python-env.ts
894
+ function findProjectRoot(cwd) {
895
+ const workspace = findUvWorkspace(cwd);
896
+ if (workspace !== null) {
897
+ return workspace.root;
898
+ }
899
+ for (const directory of ancestors2(cwd)) {
900
+ if (isFile2(join4(directory, "pyproject.toml")) || isFile2(join4(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2(join4(directory, "package.json")) || isDirectory4(join4(directory, "node_modules"))) {
696
901
  return directory;
697
902
  }
698
903
  }
699
904
  return null;
700
905
  }
701
906
  function findVenv(cwd = process.cwd()) {
907
+ const workspace = findUvWorkspace(cwd);
702
908
  const projectRoot = findProjectRoot(cwd) ?? cwd;
703
909
  const uvProjectEnvironment = process.env["UV_PROJECT_ENVIRONMENT"];
704
910
  if (uvProjectEnvironment) {
@@ -707,35 +913,38 @@ function findVenv(cwd = process.cwd()) {
707
913
  return path;
708
914
  }
709
915
  }
710
- for (const directory of ancestors(cwd)) {
916
+ if (workspace !== null) {
917
+ return venvFromDotVenv(workspace.root);
918
+ }
919
+ for (const directory of ancestors2(cwd)) {
711
920
  const venv = venvFromDotVenv(directory);
712
921
  if (venv !== null) {
713
922
  return venv;
714
923
  }
715
924
  }
716
925
  const virtualEnv = process.env["VIRTUAL_ENV"];
717
- if (virtualEnv && isVenvDir(virtualEnv) && isRelativeTo2(virtualEnv, projectRoot)) {
926
+ if (virtualEnv && isVenvDir(virtualEnv) && isRelativeTo3(virtualEnv, projectRoot)) {
718
927
  return virtualEnv;
719
928
  }
720
929
  const condaPrefix = process.env["CONDA_PREFIX"];
721
- if (condaPrefix && isDirectory3(condaPrefix)) {
930
+ if (condaPrefix && isDirectory4(condaPrefix)) {
722
931
  return condaPrefix;
723
932
  }
724
933
  return null;
725
934
  }
726
935
  function getSitePackagesDir(venvPath) {
727
936
  const windowsSitePackages = join4(venvPath, "Lib", "site-packages");
728
- if (isDirectory3(windowsSitePackages)) {
937
+ if (isDirectory4(windowsSitePackages)) {
729
938
  return windowsSitePackages;
730
939
  }
731
940
  for (const libName of ["lib", "lib64"]) {
732
941
  const libDir = join4(venvPath, libName);
733
- if (!isDirectory3(libDir)) {
942
+ if (!isDirectory4(libDir)) {
734
943
  continue;
735
944
  }
736
- for (const child of readdirSync3(libDir).sort().reverse()) {
945
+ for (const child of readdirSync4(libDir).sort().reverse()) {
737
946
  const sitePackages = join4(libDir, child, "site-packages");
738
- if (child.startsWith("python") && isDirectory3(sitePackages)) {
947
+ if (child.startsWith("python") && isDirectory4(sitePackages)) {
739
948
  return sitePackages;
740
949
  }
741
950
  }
@@ -743,23 +952,23 @@ function getSitePackagesDir(venvPath) {
743
952
  return null;
744
953
  }
745
954
  function findNodeModules(cwd = process.cwd()) {
746
- for (const directory of ancestors(cwd)) {
955
+ for (const directory of ancestors2(cwd)) {
747
956
  const nodeModules = join4(directory, "node_modules");
748
- if (isDirectory3(nodeModules)) {
957
+ if (isDirectory4(nodeModules)) {
749
958
  return nodeModules;
750
959
  }
751
960
  }
752
961
  return null;
753
962
  }
754
963
  function isVenvDir(directory) {
755
- return isFile(join4(directory, "pyvenv.cfg"));
964
+ return isFile2(join4(directory, "pyvenv.cfg"));
756
965
  }
757
966
  function venvFromDotVenv(projectRoot) {
758
967
  const dotVenv = join4(projectRoot, ".venv");
759
- if (isDirectory3(dotVenv)) {
968
+ if (isDirectory4(dotVenv)) {
760
969
  return isVenvDir(dotVenv) ? dotVenv : null;
761
970
  }
762
- if (isFile(dotVenv)) {
971
+ if (isFile2(dotVenv)) {
763
972
  return readVenvRedirectFile(dotVenv);
764
973
  }
765
974
  return null;
@@ -767,7 +976,7 @@ function venvFromDotVenv(projectRoot) {
767
976
  function readVenvRedirectFile(path) {
768
977
  let content;
769
978
  try {
770
- content = readFileSync3(path, "utf8");
979
+ content = readFileSync4(path, "utf8");
771
980
  } catch {
772
981
  return null;
773
982
  }
@@ -778,9 +987,9 @@ function readVenvRedirectFile(path) {
778
987
  const venv = isAbsolute2(redirect) ? redirect : join4(dirname3(path), redirect);
779
988
  return isVenvDir(venv) ? venv : null;
780
989
  }
781
- function ancestors(start) {
990
+ function ancestors2(start) {
782
991
  const result = [];
783
- let directory = resolve3(start);
992
+ let directory = resolve4(start);
784
993
  while (true) {
785
994
  result.push(directory);
786
995
  const parent = dirname3(directory);
@@ -791,21 +1000,21 @@ function ancestors(start) {
791
1000
  }
792
1001
  return result;
793
1002
  }
794
- function isRelativeTo2(path, parent) {
795
- const normalizedPath = resolve3(path);
796
- const normalizedParent = resolve3(parent);
797
- return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep}`);
1003
+ function isRelativeTo3(path, parent) {
1004
+ const normalizedPath = resolve4(path);
1005
+ const normalizedParent = resolve4(parent);
1006
+ return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep2}`);
798
1007
  }
799
- function isFile(path) {
1008
+ function isFile2(path) {
800
1009
  try {
801
- return statSync3(path).isFile();
1010
+ return statSync4(path).isFile();
802
1011
  } catch {
803
1012
  return false;
804
1013
  }
805
1014
  }
806
- function isDirectory3(path) {
1015
+ function isDirectory4(path) {
807
1016
  try {
808
- return statSync3(path).isDirectory();
1017
+ return statSync4(path).isDirectory();
809
1018
  } catch {
810
1019
  return false;
811
1020
  }
@@ -813,11 +1022,20 @@ function isDirectory3(path) {
813
1022
 
814
1023
  // ts/src/cli.ts
815
1024
  function getProjectContext(cwd = process.cwd()) {
816
- const projectRoot = findProjectRoot(cwd) ?? cwd;
1025
+ const workspace = findUvWorkspace(cwd);
1026
+ const projectRoot = workspace?.root ?? findProjectRoot(cwd) ?? cwd;
817
1027
  const targetEnvironment = findVenv(cwd);
818
1028
  const sitePackagesDir = targetEnvironment === null ? null : getSitePackagesDir(targetEnvironment);
819
1029
  const nodeModulesDir = findNodeModules(cwd);
820
- return { cwd, projectRoot, targetEnvironment, sitePackagesDir, nodeModulesDir };
1030
+ return {
1031
+ cwd,
1032
+ projectRoot,
1033
+ targetEnvironment,
1034
+ sitePackagesDir,
1035
+ nodeModulesDir,
1036
+ workspace,
1037
+ dependencyFiles: workspace ? workspaceDependencyFiles(workspace) : []
1038
+ };
821
1039
  }
822
1040
  function scanContext(context) {
823
1041
  const result = {
@@ -830,6 +1048,14 @@ function scanContext(context) {
830
1048
  result.skills.push(...pythonResult.skills);
831
1049
  result.warnings.push(...pythonResult.warnings);
832
1050
  }
1051
+ if (context.workspace?.currentMember) {
1052
+ const memberVenv = `${context.workspace.currentMember}/.venv`;
1053
+ if (exists(memberVenv)) {
1054
+ result.warnings.push(
1055
+ `Ignoring member-local .venv in uv workspace: ${memberVenv}`
1056
+ );
1057
+ }
1058
+ }
833
1059
  if (context.nodeModulesDir !== null) {
834
1060
  const nodeResult = scanNodePackages(context.nodeModulesDir);
835
1061
  result.skills.push(...nodeResult.skills);
@@ -851,11 +1077,13 @@ function topLevelSkills({
851
1077
  return skills;
852
1078
  }
853
1079
  const topLevelDeps = getTopLevelDeps(context.projectRoot);
854
- if (topLevelDeps === null) {
1080
+ const workspaceTopLevelDeps = context.workspace === null ? null : getWorkspaceTopLevelDeps(context.dependencyFiles);
1081
+ const selectedTopLevelDeps = context.workspace === null ? topLevelDeps : workspaceTopLevelDeps;
1082
+ if (selectedTopLevelDeps === null) {
855
1083
  return skills;
856
1084
  }
857
1085
  return skills.filter(
858
- (skill) => topLevelDeps.has(normalizePackageName(skill.packageName))
1086
+ (skill) => selectedTopLevelDeps.has(normalizePackageName(skill.packageName))
859
1087
  );
860
1088
  }
861
1089
  function printWarnings(warnings) {
@@ -867,7 +1095,7 @@ function displayPath(path, projectRoot) {
867
1095
  if (!path) {
868
1096
  return "";
869
1097
  }
870
- const relativePath = relative3(resolve4(projectRoot), resolve4(path));
1098
+ const relativePath = relative4(resolve5(projectRoot), resolve5(path));
871
1099
  if (relativePath === "") {
872
1100
  return ".";
873
1101
  }
@@ -878,6 +1106,12 @@ function displayPath(path, projectRoot) {
878
1106
  }
879
1107
  function printContext(context) {
880
1108
  console.log(`Project root: ${context.projectRoot}`);
1109
+ if (context.workspace !== null) {
1110
+ console.log(`Workspace root: ${context.workspace.root}`);
1111
+ if (context.workspace.currentMember !== null) {
1112
+ console.log(`Workspace member: ${context.workspace.currentMember}`);
1113
+ }
1114
+ }
881
1115
  console.log(
882
1116
  `Target Python environment: ${context.targetEnvironment ? displayPath(context.targetEnvironment, context.projectRoot) : "not found"}`
883
1117
  );
@@ -917,6 +1151,9 @@ function scanJsonPayload({
917
1151
  }) {
918
1152
  return {
919
1153
  project_root: context.projectRoot,
1154
+ workspace_root: context.workspace?.root ?? "",
1155
+ workspace_member: context.workspace?.currentMember ?? "",
1156
+ dependency_files: context.dependencyFiles,
920
1157
  target_environment: context.targetEnvironment ?? "",
921
1158
  node_modules: context.nodeModulesDir ?? "",
922
1159
  skills: skills.map((skill) => ({
@@ -972,13 +1209,13 @@ function installedStatuses({
972
1209
  skills
973
1210
  }) {
974
1211
  const skillsByDir = new Map(
975
- skills.map((skill) => [resolve4(skill.skillDir), skill])
1212
+ skills.map((skill) => [resolve5(skill.skillDir), skill])
976
1213
  );
977
1214
  const skillsByName = new Map(skills.map((skill) => [skill.name, skill]));
978
1215
  const statuses = [];
979
1216
  for (const target of targets) {
980
1217
  for (const installed of listInstalledSkills(target.path)) {
981
- const skill = installed.target ? skillsByDir.get(resolve4(installed.target)) : null;
1218
+ const skill = installed.target ? skillsByDir.get(resolve5(installed.target)) : null;
982
1219
  let matchedSkill = skill ?? null;
983
1220
  let status = "hand-authored";
984
1221
  if (installed.type === "symlink") {
@@ -1342,13 +1579,13 @@ function collect(value, previous) {
1342
1579
  }
1343
1580
  function exists(path) {
1344
1581
  try {
1345
- statSync4(path);
1582
+ statSync5(path);
1346
1583
  return true;
1347
1584
  } catch {
1348
1585
  return false;
1349
1586
  }
1350
1587
  }
1351
- if (process.argv[1] && realpathSync2(fileURLToPath2(import.meta.url)) === realpathSync2(resolve4(process.argv[1]))) {
1588
+ if (process.argv[1] && realpathSync2(fileURLToPath2(import.meta.url)) === realpathSync2(resolve5(process.argv[1]))) {
1352
1589
  main().catch((error) => {
1353
1590
  console.error(error);
1354
1591
  process.exit(1);
package/ts/dist/deps.cjs CHANGED
@@ -22,7 +22,9 @@ var deps_exports = {};
22
22
  __export(deps_exports, {
23
23
  getNodeTopLevelDeps: () => getNodeTopLevelDeps,
24
24
  getPythonTopLevelDeps: () => getPythonTopLevelDeps,
25
+ getPythonTopLevelDepsFromFiles: () => getPythonTopLevelDepsFromFiles,
25
26
  getTopLevelDeps: () => getTopLevelDeps,
27
+ getWorkspaceTopLevelDeps: () => getWorkspaceTopLevelDeps,
26
28
  testing: () => testing
27
29
  });
28
30
  module.exports = __toCommonJS(deps_exports);
@@ -45,13 +47,30 @@ function getPythonTopLevelDeps(projectRoot) {
45
47
  if (!(0, import_node_fs2.existsSync)(pyproject)) {
46
48
  return null;
47
49
  }
48
- let data;
49
- try {
50
- data = (0, import_smol_toml.parse)((0, import_node_fs2.readFileSync)(pyproject, "utf8"));
51
- } catch {
50
+ return getPythonTopLevelDepsFromFiles([pyproject]);
51
+ }
52
+ function getPythonTopLevelDepsFromFiles(pyprojects) {
53
+ if (pyprojects.length === 0) {
52
54
  return null;
53
55
  }
54
56
  const deps = /* @__PURE__ */ new Set();
57
+ let found = false;
58
+ for (const pyproject of pyprojects) {
59
+ if (!(0, import_node_fs2.existsSync)(pyproject)) {
60
+ continue;
61
+ }
62
+ let data;
63
+ try {
64
+ data = (0, import_smol_toml.parse)((0, import_node_fs2.readFileSync)(pyproject, "utf8"));
65
+ } catch {
66
+ return null;
67
+ }
68
+ found = true;
69
+ extractPythonTopLevelDeps(data, deps);
70
+ }
71
+ return found ? deps : null;
72
+ }
73
+ function extractPythonTopLevelDeps(data, deps) {
55
74
  const project = data["project"];
56
75
  if (isRecord(project)) {
57
76
  const dependencies = project["dependencies"];
@@ -73,7 +92,6 @@ function getPythonTopLevelDeps(projectRoot) {
73
92
  extractDepsFromDependencyGroup(groupName, dependencyGroups, deps, /* @__PURE__ */ new Set());
74
93
  }
75
94
  }
76
- return deps;
77
95
  }
78
96
  function getNodeTopLevelDeps(projectRoot) {
79
97
  const packageJson = (0, import_node_path2.join)(projectRoot, "package.json");
@@ -116,12 +134,15 @@ function getTopLevelDeps(projectRoot) {
116
134
  }
117
135
  return new Set(dependencySets.flatMap((deps) => [...deps]));
118
136
  }
137
+ function getWorkspaceTopLevelDeps(pyprojects) {
138
+ return getPythonTopLevelDepsFromFiles(pyprojects);
139
+ }
119
140
  function extractDepsFromSpecs(depSpecs, deps) {
120
141
  for (const depSpec of depSpecs) {
121
142
  if (typeof depSpec !== "string") {
122
143
  continue;
123
144
  }
124
- const packageName = depSpec.split(/[>=<![\];,\s]/)[0]?.trim();
145
+ const packageName = depSpec.split(/[~>=<![\];,\s]/)[0]?.trim();
125
146
  if (packageName && !packageName.startsWith("#")) {
126
147
  deps.add(normalizePackageName(packageName));
127
148
  }
@@ -164,6 +185,8 @@ var testing = {
164
185
  0 && (module.exports = {
165
186
  getNodeTopLevelDeps,
166
187
  getPythonTopLevelDeps,
188
+ getPythonTopLevelDepsFromFiles,
167
189
  getTopLevelDeps,
190
+ getWorkspaceTopLevelDeps,
168
191
  testing
169
192
  });
@@ -1,6 +1,8 @@
1
1
  declare function getPythonTopLevelDeps(projectRoot: string): Set<string> | null;
2
+ declare function getPythonTopLevelDepsFromFiles(pyprojects: string[]): Set<string> | null;
2
3
  declare function getNodeTopLevelDeps(projectRoot: string): Set<string> | null;
3
4
  declare function getTopLevelDeps(projectRoot: string): Set<string> | null;
5
+ declare function getWorkspaceTopLevelDeps(pyprojects: string[]): Set<string> | null;
4
6
  declare function extractDepsFromSpecs(depSpecs: unknown[], deps: Set<string>): void;
5
7
  declare function extractDepsFromDependencyGroup(groupName: unknown, dependencyGroups: Record<string, unknown>, deps: Set<string>, visited: Set<unknown>): void;
6
8
  declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -10,4 +12,4 @@ declare const testing: {
10
12
  isRecord: typeof isRecord;
11
13
  };
12
14
 
13
- export { getNodeTopLevelDeps, getPythonTopLevelDeps, getTopLevelDeps, testing };
15
+ export { getNodeTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };
package/ts/dist/deps.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  declare function getPythonTopLevelDeps(projectRoot: string): Set<string> | null;
2
+ declare function getPythonTopLevelDepsFromFiles(pyprojects: string[]): Set<string> | null;
2
3
  declare function getNodeTopLevelDeps(projectRoot: string): Set<string> | null;
3
4
  declare function getTopLevelDeps(projectRoot: string): Set<string> | null;
5
+ declare function getWorkspaceTopLevelDeps(pyprojects: string[]): Set<string> | null;
4
6
  declare function extractDepsFromSpecs(depSpecs: unknown[], deps: Set<string>): void;
5
7
  declare function extractDepsFromDependencyGroup(groupName: unknown, dependencyGroups: Record<string, unknown>, deps: Set<string>, visited: Set<unknown>): void;
6
8
  declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -10,4 +12,4 @@ declare const testing: {
10
12
  isRecord: typeof isRecord;
11
13
  };
12
14
 
13
- export { getNodeTopLevelDeps, getPythonTopLevelDeps, getTopLevelDeps, testing };
15
+ export { getNodeTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };