library-skills 0.0.6 → 0.0.9
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 +1 -1
- package/ts/dist/cli.d.ts +8 -0
- package/ts/dist/cli.js +320 -56
- package/ts/dist/deps.cjs +72 -18
- package/ts/dist/deps.d.cts +5 -1
- package/ts/dist/deps.d.ts +5 -1
- package/ts/dist/deps.js +70 -18
- package/ts/dist/python-env.cjs +211 -33
- package/ts/dist/python-env.js +205 -27
package/package.json
CHANGED
package/ts/dist/cli.d.ts
CHANGED
|
@@ -15,12 +15,20 @@ interface InstallTarget {
|
|
|
15
15
|
path: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
interface UvWorkspace {
|
|
19
|
+
root: string;
|
|
20
|
+
members: string[];
|
|
21
|
+
currentMember: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
interface ProjectContext {
|
|
19
25
|
cwd: string;
|
|
20
26
|
projectRoot: string;
|
|
21
27
|
targetEnvironment: string | null;
|
|
22
28
|
sitePackagesDir: string | null;
|
|
23
29
|
nodeModulesDir: string | null;
|
|
30
|
+
workspace: UvWorkspace | null;
|
|
31
|
+
dependencyFiles: string[];
|
|
24
32
|
}
|
|
25
33
|
interface InstalledStatus {
|
|
26
34
|
target: InstallTarget;
|
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
|
|
7
|
-
import { isAbsolute as isAbsolute3, relative as
|
|
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
|
|
@@ -468,30 +468,51 @@ function getPythonTopLevelDeps(projectRoot) {
|
|
|
468
468
|
if (!existsSync2(pyproject)) {
|
|
469
469
|
return null;
|
|
470
470
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
471
|
+
return getPythonTopLevelDepsFromFiles([pyproject]);
|
|
472
|
+
}
|
|
473
|
+
function getPythonTopLevelDepsFromFiles(pyprojects) {
|
|
474
|
+
if (pyprojects.length === 0) {
|
|
475
475
|
return null;
|
|
476
476
|
}
|
|
477
477
|
const deps = /* @__PURE__ */ new Set();
|
|
478
|
+
let found = false;
|
|
479
|
+
for (const pyproject of pyprojects) {
|
|
480
|
+
if (!existsSync2(pyproject)) {
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
let data;
|
|
484
|
+
try {
|
|
485
|
+
data = parse2(readFileSync2(pyproject, "utf8"));
|
|
486
|
+
} catch {
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
found = true;
|
|
490
|
+
extractPythonTopLevelDeps(data, deps);
|
|
491
|
+
}
|
|
492
|
+
return found ? deps : null;
|
|
493
|
+
}
|
|
494
|
+
function extractPythonTopLevelDeps(data, deps) {
|
|
478
495
|
const project = data["project"];
|
|
479
|
-
if (
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
extractDepsFromSpecs(groupDependencies, deps);
|
|
496
|
+
if (isRecord2(project)) {
|
|
497
|
+
const dependencies = project["dependencies"];
|
|
498
|
+
if (Array.isArray(dependencies)) {
|
|
499
|
+
extractDepsFromSpecs(dependencies, deps);
|
|
500
|
+
}
|
|
501
|
+
const optionalDependencies = project["optional-dependencies"];
|
|
502
|
+
if (isRecord2(optionalDependencies)) {
|
|
503
|
+
for (const groupDependencies of Object.values(optionalDependencies)) {
|
|
504
|
+
if (Array.isArray(groupDependencies)) {
|
|
505
|
+
extractDepsFromSpecs(groupDependencies, deps);
|
|
506
|
+
}
|
|
491
507
|
}
|
|
492
508
|
}
|
|
493
509
|
}
|
|
494
|
-
|
|
510
|
+
const dependencyGroups = data["dependency-groups"];
|
|
511
|
+
if (isRecord2(dependencyGroups)) {
|
|
512
|
+
for (const groupName of Object.keys(dependencyGroups)) {
|
|
513
|
+
extractDepsFromDependencyGroup(groupName, dependencyGroups, deps, /* @__PURE__ */ new Set());
|
|
514
|
+
}
|
|
515
|
+
}
|
|
495
516
|
}
|
|
496
517
|
function getNodeTopLevelDeps(projectRoot) {
|
|
497
518
|
const packageJson = join2(projectRoot, "package.json");
|
|
@@ -534,17 +555,45 @@ function getTopLevelDeps(projectRoot) {
|
|
|
534
555
|
}
|
|
535
556
|
return new Set(dependencySets.flatMap((deps) => [...deps]));
|
|
536
557
|
}
|
|
558
|
+
function getWorkspaceTopLevelDeps(pyprojects) {
|
|
559
|
+
return getPythonTopLevelDepsFromFiles(pyprojects);
|
|
560
|
+
}
|
|
537
561
|
function extractDepsFromSpecs(depSpecs, deps) {
|
|
538
562
|
for (const depSpec of depSpecs) {
|
|
539
563
|
if (typeof depSpec !== "string") {
|
|
540
564
|
continue;
|
|
541
565
|
}
|
|
542
|
-
const packageName = depSpec.split(/[
|
|
566
|
+
const packageName = depSpec.split(/[~>=<![\];,\s]/)[0]?.trim();
|
|
543
567
|
if (packageName && !packageName.startsWith("#")) {
|
|
544
568
|
deps.add(normalizePackageName(packageName));
|
|
545
569
|
}
|
|
546
570
|
}
|
|
547
571
|
}
|
|
572
|
+
function extractDepsFromDependencyGroup(groupName, dependencyGroups, deps, visited) {
|
|
573
|
+
if (visited.has(groupName)) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
visited.add(groupName);
|
|
577
|
+
if (typeof groupName !== "string") {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
const groupDependencies = dependencyGroups[groupName];
|
|
581
|
+
if (!Array.isArray(groupDependencies)) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
extractDepsFromSpecs(groupDependencies, deps);
|
|
585
|
+
for (const groupDependency of groupDependencies) {
|
|
586
|
+
if (!isRecord2(groupDependency)) {
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
extractDepsFromDependencyGroup(
|
|
590
|
+
groupDependency["include-group"],
|
|
591
|
+
dependencyGroups,
|
|
592
|
+
deps,
|
|
593
|
+
visited
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
548
597
|
function isRecord2(value) {
|
|
549
598
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
550
599
|
}
|
|
@@ -658,17 +707,201 @@ function isDirectory2(path) {
|
|
|
658
707
|
}
|
|
659
708
|
|
|
660
709
|
// ts/src/python-env.ts
|
|
661
|
-
import { readFileSync as
|
|
662
|
-
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as
|
|
663
|
-
|
|
710
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
711
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve4, sep as sep2 } from "path";
|
|
712
|
+
|
|
713
|
+
// ts/src/workspace.ts
|
|
714
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
715
|
+
import { relative as relative3, resolve as resolve3, sep } from "path";
|
|
716
|
+
import { parse as parse3 } from "smol-toml";
|
|
717
|
+
function findUvWorkspace(cwd) {
|
|
664
718
|
for (const directory of ancestors(cwd)) {
|
|
665
|
-
|
|
719
|
+
const pyproject = `${directory}/pyproject.toml`;
|
|
720
|
+
if (!existsSync4(pyproject)) {
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
const data = readPyproject(pyproject);
|
|
724
|
+
if (!hasUvWorkspace(data)) {
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
const members = findWorkspaceMembers(directory, data);
|
|
728
|
+
return {
|
|
729
|
+
root: directory,
|
|
730
|
+
members,
|
|
731
|
+
currentMember: findCurrentMember(cwd, members)
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
function workspaceDependencyFiles(workspace) {
|
|
737
|
+
if (workspace.currentMember !== null) {
|
|
738
|
+
return [`${workspace.currentMember}/pyproject.toml`];
|
|
739
|
+
}
|
|
740
|
+
return [
|
|
741
|
+
`${workspace.root}/pyproject.toml`,
|
|
742
|
+
...workspace.members.map((member) => `${member}/pyproject.toml`)
|
|
743
|
+
].filter((path) => existsSync4(path));
|
|
744
|
+
}
|
|
745
|
+
function readPyproject(path) {
|
|
746
|
+
try {
|
|
747
|
+
const data = parse3(readFileSync3(path, "utf8"));
|
|
748
|
+
return isRecord3(data) ? data : {};
|
|
749
|
+
} catch {
|
|
750
|
+
return {};
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function hasUvWorkspace(data) {
|
|
754
|
+
const tool = data["tool"];
|
|
755
|
+
if (!isRecord3(tool)) {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
const uv = tool["uv"];
|
|
759
|
+
if (!isRecord3(uv)) {
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
return isRecord3(uv["workspace"]);
|
|
763
|
+
}
|
|
764
|
+
function findWorkspaceMembers(root, data) {
|
|
765
|
+
const workspace = getWorkspaceTable(data);
|
|
766
|
+
if (workspace === null || !Array.isArray(workspace["members"])) {
|
|
767
|
+
return [];
|
|
768
|
+
}
|
|
769
|
+
const excludes = Array.isArray(workspace["exclude"]) ? workspace["exclude"].filter(
|
|
770
|
+
(value) => typeof value === "string"
|
|
771
|
+
) : [];
|
|
772
|
+
const members = /* @__PURE__ */ new Set();
|
|
773
|
+
for (const memberGlob of workspace["members"]) {
|
|
774
|
+
if (typeof memberGlob !== "string") {
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
for (const member of expandMemberGlob(root, memberGlob)) {
|
|
778
|
+
const relativePath = relative3(root, member).split(sep).join("/");
|
|
779
|
+
if (isExcluded(relativePath, excludes)) {
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
if (isFile(`${member}/pyproject.toml`)) {
|
|
783
|
+
members.add(resolve3(member));
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return [...members].sort();
|
|
788
|
+
}
|
|
789
|
+
function getWorkspaceTable(data) {
|
|
790
|
+
const tool = data["tool"];
|
|
791
|
+
if (!isRecord3(tool)) {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
const uv = tool["uv"];
|
|
795
|
+
if (!isRecord3(uv)) {
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
const workspace = uv["workspace"];
|
|
799
|
+
return isRecord3(workspace) ? workspace : null;
|
|
800
|
+
}
|
|
801
|
+
function expandMemberGlob(root, pattern) {
|
|
802
|
+
const parts = pattern.split("/");
|
|
803
|
+
const results = [];
|
|
804
|
+
walkGlob(root, parts, results);
|
|
805
|
+
return results;
|
|
806
|
+
}
|
|
807
|
+
function walkGlob(directory, parts, results) {
|
|
808
|
+
if (parts.length === 0) {
|
|
809
|
+
if (isDirectory3(directory)) {
|
|
810
|
+
results.push(directory);
|
|
811
|
+
}
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
const [part, ...rest] = parts;
|
|
815
|
+
if (part === "*") {
|
|
816
|
+
for (const entry of readDirSafe(directory)) {
|
|
817
|
+
const child = `${directory}/${entry}`;
|
|
818
|
+
if (isDirectory3(child)) {
|
|
819
|
+
walkGlob(child, rest, results);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
walkGlob(`${directory}/${part}`, rest, results);
|
|
825
|
+
}
|
|
826
|
+
function isExcluded(relativePath, excludes) {
|
|
827
|
+
return excludes.some(
|
|
828
|
+
(pattern) => globMatches(relativePath, pattern.replace(/\/$/, ""))
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
function globMatches(value, pattern) {
|
|
832
|
+
if (pattern === value) {
|
|
833
|
+
return true;
|
|
834
|
+
}
|
|
835
|
+
const regex = new RegExp(`^${pattern.split("*").map(escapeRegex).join(".*")}$`);
|
|
836
|
+
return regex.test(value);
|
|
837
|
+
}
|
|
838
|
+
function findCurrentMember(cwd, members) {
|
|
839
|
+
const resolvedCwd = resolve3(cwd);
|
|
840
|
+
const matches = members.filter((member) => isRelativeTo2(resolvedCwd, member));
|
|
841
|
+
if (matches.length === 0) {
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
return matches.sort((left, right) => right.length - left.length)[0] ?? null;
|
|
845
|
+
}
|
|
846
|
+
function ancestors(start) {
|
|
847
|
+
const result = [];
|
|
848
|
+
let directory = resolve3(start);
|
|
849
|
+
while (true) {
|
|
850
|
+
result.push(directory);
|
|
851
|
+
const parent = resolve3(directory, "..");
|
|
852
|
+
if (parent === directory) {
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
directory = parent;
|
|
856
|
+
}
|
|
857
|
+
return result;
|
|
858
|
+
}
|
|
859
|
+
function isRelativeTo2(path, parent) {
|
|
860
|
+
const normalizedPath = resolve3(path);
|
|
861
|
+
const normalizedParent = resolve3(parent);
|
|
862
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep}`);
|
|
863
|
+
}
|
|
864
|
+
function isRecord3(value) {
|
|
865
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
866
|
+
}
|
|
867
|
+
function isFile(path) {
|
|
868
|
+
try {
|
|
869
|
+
return statSync3(path).isFile();
|
|
870
|
+
} catch {
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function isDirectory3(path) {
|
|
875
|
+
try {
|
|
876
|
+
return statSync3(path).isDirectory();
|
|
877
|
+
} catch {
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function readDirSafe(path) {
|
|
882
|
+
try {
|
|
883
|
+
return isDirectory3(path) ? readdirSync3(path) : [];
|
|
884
|
+
} catch {
|
|
885
|
+
return [];
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
var escapeRegex = (value) => value.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
889
|
+
|
|
890
|
+
// ts/src/python-env.ts
|
|
891
|
+
function findProjectRoot(cwd) {
|
|
892
|
+
const workspace = findUvWorkspace(cwd);
|
|
893
|
+
if (workspace !== null) {
|
|
894
|
+
return workspace.root;
|
|
895
|
+
}
|
|
896
|
+
for (const directory of ancestors2(cwd)) {
|
|
897
|
+
if (isFile2(join4(directory, "pyproject.toml")) || isFile2(join4(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2(join4(directory, "package.json")) || isDirectory4(join4(directory, "node_modules"))) {
|
|
666
898
|
return directory;
|
|
667
899
|
}
|
|
668
900
|
}
|
|
669
901
|
return null;
|
|
670
902
|
}
|
|
671
903
|
function findVenv(cwd = process.cwd()) {
|
|
904
|
+
const workspace = findUvWorkspace(cwd);
|
|
672
905
|
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
673
906
|
const uvProjectEnvironment = process.env["UV_PROJECT_ENVIRONMENT"];
|
|
674
907
|
if (uvProjectEnvironment) {
|
|
@@ -677,35 +910,38 @@ function findVenv(cwd = process.cwd()) {
|
|
|
677
910
|
return path;
|
|
678
911
|
}
|
|
679
912
|
}
|
|
680
|
-
|
|
913
|
+
if (workspace !== null) {
|
|
914
|
+
return venvFromDotVenv(workspace.root);
|
|
915
|
+
}
|
|
916
|
+
for (const directory of ancestors2(cwd)) {
|
|
681
917
|
const venv = venvFromDotVenv(directory);
|
|
682
918
|
if (venv !== null) {
|
|
683
919
|
return venv;
|
|
684
920
|
}
|
|
685
921
|
}
|
|
686
922
|
const virtualEnv = process.env["VIRTUAL_ENV"];
|
|
687
|
-
if (virtualEnv && isVenvDir(virtualEnv) &&
|
|
923
|
+
if (virtualEnv && isVenvDir(virtualEnv) && isRelativeTo3(virtualEnv, projectRoot)) {
|
|
688
924
|
return virtualEnv;
|
|
689
925
|
}
|
|
690
926
|
const condaPrefix = process.env["CONDA_PREFIX"];
|
|
691
|
-
if (condaPrefix &&
|
|
927
|
+
if (condaPrefix && isDirectory4(condaPrefix)) {
|
|
692
928
|
return condaPrefix;
|
|
693
929
|
}
|
|
694
930
|
return null;
|
|
695
931
|
}
|
|
696
932
|
function getSitePackagesDir(venvPath) {
|
|
697
933
|
const windowsSitePackages = join4(venvPath, "Lib", "site-packages");
|
|
698
|
-
if (
|
|
934
|
+
if (isDirectory4(windowsSitePackages)) {
|
|
699
935
|
return windowsSitePackages;
|
|
700
936
|
}
|
|
701
937
|
for (const libName of ["lib", "lib64"]) {
|
|
702
938
|
const libDir = join4(venvPath, libName);
|
|
703
|
-
if (!
|
|
939
|
+
if (!isDirectory4(libDir)) {
|
|
704
940
|
continue;
|
|
705
941
|
}
|
|
706
|
-
for (const child of
|
|
942
|
+
for (const child of readdirSync4(libDir).sort().reverse()) {
|
|
707
943
|
const sitePackages = join4(libDir, child, "site-packages");
|
|
708
|
-
if (child.startsWith("python") &&
|
|
944
|
+
if (child.startsWith("python") && isDirectory4(sitePackages)) {
|
|
709
945
|
return sitePackages;
|
|
710
946
|
}
|
|
711
947
|
}
|
|
@@ -713,23 +949,23 @@ function getSitePackagesDir(venvPath) {
|
|
|
713
949
|
return null;
|
|
714
950
|
}
|
|
715
951
|
function findNodeModules(cwd = process.cwd()) {
|
|
716
|
-
for (const directory of
|
|
952
|
+
for (const directory of ancestors2(cwd)) {
|
|
717
953
|
const nodeModules = join4(directory, "node_modules");
|
|
718
|
-
if (
|
|
954
|
+
if (isDirectory4(nodeModules)) {
|
|
719
955
|
return nodeModules;
|
|
720
956
|
}
|
|
721
957
|
}
|
|
722
958
|
return null;
|
|
723
959
|
}
|
|
724
960
|
function isVenvDir(directory) {
|
|
725
|
-
return
|
|
961
|
+
return isFile2(join4(directory, "pyvenv.cfg"));
|
|
726
962
|
}
|
|
727
963
|
function venvFromDotVenv(projectRoot) {
|
|
728
964
|
const dotVenv = join4(projectRoot, ".venv");
|
|
729
|
-
if (
|
|
965
|
+
if (isDirectory4(dotVenv)) {
|
|
730
966
|
return isVenvDir(dotVenv) ? dotVenv : null;
|
|
731
967
|
}
|
|
732
|
-
if (
|
|
968
|
+
if (isFile2(dotVenv)) {
|
|
733
969
|
return readVenvRedirectFile(dotVenv);
|
|
734
970
|
}
|
|
735
971
|
return null;
|
|
@@ -737,7 +973,7 @@ function venvFromDotVenv(projectRoot) {
|
|
|
737
973
|
function readVenvRedirectFile(path) {
|
|
738
974
|
let content;
|
|
739
975
|
try {
|
|
740
|
-
content =
|
|
976
|
+
content = readFileSync4(path, "utf8");
|
|
741
977
|
} catch {
|
|
742
978
|
return null;
|
|
743
979
|
}
|
|
@@ -748,9 +984,9 @@ function readVenvRedirectFile(path) {
|
|
|
748
984
|
const venv = isAbsolute2(redirect) ? redirect : join4(dirname3(path), redirect);
|
|
749
985
|
return isVenvDir(venv) ? venv : null;
|
|
750
986
|
}
|
|
751
|
-
function
|
|
987
|
+
function ancestors2(start) {
|
|
752
988
|
const result = [];
|
|
753
|
-
let directory =
|
|
989
|
+
let directory = resolve4(start);
|
|
754
990
|
while (true) {
|
|
755
991
|
result.push(directory);
|
|
756
992
|
const parent = dirname3(directory);
|
|
@@ -761,21 +997,21 @@ function ancestors(start) {
|
|
|
761
997
|
}
|
|
762
998
|
return result;
|
|
763
999
|
}
|
|
764
|
-
function
|
|
765
|
-
const normalizedPath =
|
|
766
|
-
const normalizedParent =
|
|
767
|
-
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${
|
|
1000
|
+
function isRelativeTo3(path, parent) {
|
|
1001
|
+
const normalizedPath = resolve4(path);
|
|
1002
|
+
const normalizedParent = resolve4(parent);
|
|
1003
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep2}`);
|
|
768
1004
|
}
|
|
769
|
-
function
|
|
1005
|
+
function isFile2(path) {
|
|
770
1006
|
try {
|
|
771
|
-
return
|
|
1007
|
+
return statSync4(path).isFile();
|
|
772
1008
|
} catch {
|
|
773
1009
|
return false;
|
|
774
1010
|
}
|
|
775
1011
|
}
|
|
776
|
-
function
|
|
1012
|
+
function isDirectory4(path) {
|
|
777
1013
|
try {
|
|
778
|
-
return
|
|
1014
|
+
return statSync4(path).isDirectory();
|
|
779
1015
|
} catch {
|
|
780
1016
|
return false;
|
|
781
1017
|
}
|
|
@@ -783,11 +1019,20 @@ function isDirectory3(path) {
|
|
|
783
1019
|
|
|
784
1020
|
// ts/src/cli.ts
|
|
785
1021
|
function getProjectContext(cwd = process.cwd()) {
|
|
786
|
-
const
|
|
1022
|
+
const workspace = findUvWorkspace(cwd);
|
|
1023
|
+
const projectRoot = workspace?.root ?? findProjectRoot(cwd) ?? cwd;
|
|
787
1024
|
const targetEnvironment = findVenv(cwd);
|
|
788
1025
|
const sitePackagesDir = targetEnvironment === null ? null : getSitePackagesDir(targetEnvironment);
|
|
789
1026
|
const nodeModulesDir = findNodeModules(cwd);
|
|
790
|
-
return {
|
|
1027
|
+
return {
|
|
1028
|
+
cwd,
|
|
1029
|
+
projectRoot,
|
|
1030
|
+
targetEnvironment,
|
|
1031
|
+
sitePackagesDir,
|
|
1032
|
+
nodeModulesDir,
|
|
1033
|
+
workspace,
|
|
1034
|
+
dependencyFiles: workspace ? workspaceDependencyFiles(workspace) : []
|
|
1035
|
+
};
|
|
791
1036
|
}
|
|
792
1037
|
function scanContext(context) {
|
|
793
1038
|
const result = {
|
|
@@ -800,6 +1045,14 @@ function scanContext(context) {
|
|
|
800
1045
|
result.skills.push(...pythonResult.skills);
|
|
801
1046
|
result.warnings.push(...pythonResult.warnings);
|
|
802
1047
|
}
|
|
1048
|
+
if (context.workspace?.currentMember) {
|
|
1049
|
+
const memberVenv = `${context.workspace.currentMember}/.venv`;
|
|
1050
|
+
if (exists(memberVenv)) {
|
|
1051
|
+
result.warnings.push(
|
|
1052
|
+
`Ignoring member-local .venv in uv workspace: ${memberVenv}`
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
803
1056
|
if (context.nodeModulesDir !== null) {
|
|
804
1057
|
const nodeResult = scanNodePackages(context.nodeModulesDir);
|
|
805
1058
|
result.skills.push(...nodeResult.skills);
|
|
@@ -821,11 +1074,13 @@ function topLevelSkills({
|
|
|
821
1074
|
return skills;
|
|
822
1075
|
}
|
|
823
1076
|
const topLevelDeps = getTopLevelDeps(context.projectRoot);
|
|
824
|
-
|
|
1077
|
+
const workspaceTopLevelDeps = context.workspace === null ? null : getWorkspaceTopLevelDeps(context.dependencyFiles);
|
|
1078
|
+
const selectedTopLevelDeps = context.workspace === null ? topLevelDeps : workspaceTopLevelDeps;
|
|
1079
|
+
if (selectedTopLevelDeps === null) {
|
|
825
1080
|
return skills;
|
|
826
1081
|
}
|
|
827
1082
|
return skills.filter(
|
|
828
|
-
(skill) =>
|
|
1083
|
+
(skill) => selectedTopLevelDeps.has(normalizePackageName(skill.packageName))
|
|
829
1084
|
);
|
|
830
1085
|
}
|
|
831
1086
|
function printWarnings(warnings) {
|
|
@@ -837,7 +1092,7 @@ function displayPath(path, projectRoot) {
|
|
|
837
1092
|
if (!path) {
|
|
838
1093
|
return "";
|
|
839
1094
|
}
|
|
840
|
-
const relativePath =
|
|
1095
|
+
const relativePath = relative4(resolve5(projectRoot), resolve5(path));
|
|
841
1096
|
if (relativePath === "") {
|
|
842
1097
|
return ".";
|
|
843
1098
|
}
|
|
@@ -848,6 +1103,12 @@ function displayPath(path, projectRoot) {
|
|
|
848
1103
|
}
|
|
849
1104
|
function printContext(context) {
|
|
850
1105
|
console.log(`Project root: ${context.projectRoot}`);
|
|
1106
|
+
if (context.workspace !== null) {
|
|
1107
|
+
console.log(`Workspace root: ${context.workspace.root}`);
|
|
1108
|
+
if (context.workspace.currentMember !== null) {
|
|
1109
|
+
console.log(`Workspace member: ${context.workspace.currentMember}`);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
851
1112
|
console.log(
|
|
852
1113
|
`Target Python environment: ${context.targetEnvironment ? displayPath(context.targetEnvironment, context.projectRoot) : "not found"}`
|
|
853
1114
|
);
|
|
@@ -887,6 +1148,9 @@ function scanJsonPayload({
|
|
|
887
1148
|
}) {
|
|
888
1149
|
return {
|
|
889
1150
|
project_root: context.projectRoot,
|
|
1151
|
+
workspace_root: context.workspace?.root ?? "",
|
|
1152
|
+
workspace_member: context.workspace?.currentMember ?? "",
|
|
1153
|
+
dependency_files: context.dependencyFiles,
|
|
890
1154
|
target_environment: context.targetEnvironment ?? "",
|
|
891
1155
|
node_modules: context.nodeModulesDir ?? "",
|
|
892
1156
|
skills: skills.map((skill) => ({
|
|
@@ -942,13 +1206,13 @@ function installedStatuses({
|
|
|
942
1206
|
skills
|
|
943
1207
|
}) {
|
|
944
1208
|
const skillsByDir = new Map(
|
|
945
|
-
skills.map((skill) => [
|
|
1209
|
+
skills.map((skill) => [resolve5(skill.skillDir), skill])
|
|
946
1210
|
);
|
|
947
1211
|
const skillsByName = new Map(skills.map((skill) => [skill.name, skill]));
|
|
948
1212
|
const statuses = [];
|
|
949
1213
|
for (const target of targets) {
|
|
950
1214
|
for (const installed of listInstalledSkills(target.path)) {
|
|
951
|
-
const skill = installed.target ? skillsByDir.get(
|
|
1215
|
+
const skill = installed.target ? skillsByDir.get(resolve5(installed.target)) : null;
|
|
952
1216
|
let matchedSkill = skill ?? null;
|
|
953
1217
|
let status = "hand-authored";
|
|
954
1218
|
if (installed.type === "symlink") {
|
|
@@ -1312,13 +1576,13 @@ function collect(value, previous) {
|
|
|
1312
1576
|
}
|
|
1313
1577
|
function exists(path) {
|
|
1314
1578
|
try {
|
|
1315
|
-
|
|
1579
|
+
statSync5(path);
|
|
1316
1580
|
return true;
|
|
1317
1581
|
} catch {
|
|
1318
1582
|
return false;
|
|
1319
1583
|
}
|
|
1320
1584
|
}
|
|
1321
|
-
if (process.argv[1] && realpathSync2(fileURLToPath2(import.meta.url)) === realpathSync2(
|
|
1585
|
+
if (process.argv[1] && realpathSync2(fileURLToPath2(import.meta.url)) === realpathSync2(resolve5(process.argv[1]))) {
|
|
1322
1586
|
main().catch((error) => {
|
|
1323
1587
|
console.error(error);
|
|
1324
1588
|
process.exit(1);
|