@agentxm/extension-discovery 0.28.4-bootstrap.0
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/LICENSE +110 -0
- package/dist/src/discover.d.ts +34 -0
- package/dist/src/discover.js +133 -0
- package/dist/src/index.d.ts +13 -0
- package/dist/src/index.js +12 -0
- package/dist/src/internal/environment.d.ts +14 -0
- package/dist/src/internal/environment.js +15 -0
- package/dist/src/packaging/bazel.d.ts +27 -0
- package/dist/src/packaging/bazel.js +125 -0
- package/dist/src/packaging/cargo.d.ts +32 -0
- package/dist/src/packaging/cargo.js +270 -0
- package/dist/src/packaging/cocoapods.d.ts +26 -0
- package/dist/src/packaging/cocoapods.js +187 -0
- package/dist/src/packaging/composer.d.ts +26 -0
- package/dist/src/packaging/composer.js +144 -0
- package/dist/src/packaging/conan.d.ts +30 -0
- package/dist/src/packaging/conan.js +238 -0
- package/dist/src/packaging/conda.d.ts +26 -0
- package/dist/src/packaging/conda.js +320 -0
- package/dist/src/packaging/cpan.d.ts +29 -0
- package/dist/src/packaging/cpan.js +189 -0
- package/dist/src/packaging/cran.d.ts +29 -0
- package/dist/src/packaging/cran.js +176 -0
- package/dist/src/packaging/detect.d.ts +16 -0
- package/dist/src/packaging/detect.js +25 -0
- package/dist/src/packaging/detected-package.d.ts +14 -0
- package/dist/src/packaging/detected-package.js +20 -0
- package/dist/src/packaging/docker.d.ts +27 -0
- package/dist/src/packaging/docker.js +256 -0
- package/dist/src/packaging/gem.d.ts +26 -0
- package/dist/src/packaging/gem.js +234 -0
- package/dist/src/packaging/golang.d.ts +26 -0
- package/dist/src/packaging/golang.js +169 -0
- package/dist/src/packaging/hackage.d.ts +26 -0
- package/dist/src/packaging/hackage.js +305 -0
- package/dist/src/packaging/hex.d.ts +28 -0
- package/dist/src/packaging/hex.js +186 -0
- package/dist/src/packaging/huggingface.d.ts +20 -0
- package/dist/src/packaging/huggingface.js +112 -0
- package/dist/src/packaging/index.d.ts +44 -0
- package/dist/src/packaging/index.js +120 -0
- package/dist/src/packaging/jsr.d.ts +30 -0
- package/dist/src/packaging/jsr.js +227 -0
- package/dist/src/packaging/julia.d.ts +27 -0
- package/dist/src/packaging/julia.js +165 -0
- package/dist/src/packaging/luarocks.d.ts +28 -0
- package/dist/src/packaging/luarocks.js +159 -0
- package/dist/src/packaging/maven.d.ts +27 -0
- package/dist/src/packaging/maven.js +471 -0
- package/dist/src/packaging/mojo.d.ts +29 -0
- package/dist/src/packaging/mojo.js +148 -0
- package/dist/src/packaging/npm.d.ts +26 -0
- package/dist/src/packaging/npm.js +190 -0
- package/dist/src/packaging/nuget.d.ts +26 -0
- package/dist/src/packaging/nuget.js +240 -0
- package/dist/src/packaging/opam.d.ts +27 -0
- package/dist/src/packaging/opam.js +287 -0
- package/dist/src/packaging/pub.d.ts +26 -0
- package/dist/src/packaging/pub.js +357 -0
- package/dist/src/packaging/pypi.d.ts +23 -0
- package/dist/src/packaging/pypi.js +448 -0
- package/dist/src/packaging/read.d.ts +20 -0
- package/dist/src/packaging/read.js +31 -0
- package/dist/src/packaging/reader-io.d.ts +29 -0
- package/dist/src/packaging/reader-io.js +29 -0
- package/dist/src/packaging/swift.d.ts +26 -0
- package/dist/src/packaging/swift.js +141 -0
- package/dist/src/packaging/types.d.ts +43 -0
- package/dist/src/packaging/types.js +8 -0
- package/dist/src/packaging/zig.d.ts +32 -0
- package/dist/src/packaging/zig.js +151 -0
- package/package.json +54 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPAN (Perl) package detector and reader for package-compatibility discovery.
|
|
3
|
+
*
|
|
4
|
+
* Parses `cpanfile` (`requires 'Name'` lines) and `Makefile.PL` (`PREREQ_PM`).
|
|
5
|
+
* Reads `x_axm` from `<lib-path>/.meta/<dist>/MYMETA.json`.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import * as Effect from "effect/Effect";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
12
|
+
import * as Path from "effect/Path";
|
|
13
|
+
import * as Result from "effect/Result";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import { readEnv } from "../internal/environment.js";
|
|
16
|
+
import { PackageTypeSchema } from "@agentxm/extension-model/unstable/packaging/package-type";
|
|
17
|
+
import { decodeAxmMeta, parseJsonOptional, readFileOptional } from "./reader-io.js";
|
|
18
|
+
const cpanType = Schema.decodeUnknownSync(PackageTypeSchema)("cpan");
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Helpers
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/**
|
|
23
|
+
* Convert a Perl module name to a CPAN distribution-style name.
|
|
24
|
+
* Module names use :: as separator (e.g., Moose::Util),
|
|
25
|
+
* distribution names use - (e.g., Moose-Util).
|
|
26
|
+
*/
|
|
27
|
+
const moduleToDistName = (moduleName) => moduleName.replace(/::/g, "-");
|
|
28
|
+
/**
|
|
29
|
+
* Parse a `cpanfile` and extract dependencies.
|
|
30
|
+
* Format: requires 'Module::Name', 'version';
|
|
31
|
+
* requires 'Module::Name';
|
|
32
|
+
*/
|
|
33
|
+
const parseCpanfile = (content, source) => {
|
|
34
|
+
const results = [];
|
|
35
|
+
const seenNames = new Set();
|
|
36
|
+
// Match: requires 'Name' or requires 'Name', 'version'
|
|
37
|
+
// Also: requires "Name" or requires "Name", "version"
|
|
38
|
+
const requiresRegex = /requires\s+['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]*)['"]\s*)?;/g;
|
|
39
|
+
let match;
|
|
40
|
+
while ((match = requiresRegex.exec(content)) !== null) {
|
|
41
|
+
const moduleName = match[1];
|
|
42
|
+
if (moduleName === undefined)
|
|
43
|
+
continue;
|
|
44
|
+
const name = moduleToDistName(moduleName);
|
|
45
|
+
if (seenNames.has(name))
|
|
46
|
+
continue;
|
|
47
|
+
seenNames.add(name);
|
|
48
|
+
const versionSpec = match[2]?.trim();
|
|
49
|
+
// Only exact versions (no ranges)
|
|
50
|
+
const version = versionSpec !== undefined && /^\d+(?:\.\d+)*$/.test(versionSpec) ? versionSpec : undefined;
|
|
51
|
+
results.push({
|
|
52
|
+
purl: {
|
|
53
|
+
type: cpanType,
|
|
54
|
+
name,
|
|
55
|
+
...(version !== undefined ? { version } : {}),
|
|
56
|
+
},
|
|
57
|
+
type: cpanType,
|
|
58
|
+
source,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return results;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Parse `Makefile.PL` and extract dependencies from PREREQ_PM.
|
|
65
|
+
* Format: PREREQ_PM => { 'Module::Name' => 'version', ... }
|
|
66
|
+
*/
|
|
67
|
+
const parseMakefilePL = (content, source) => {
|
|
68
|
+
const results = [];
|
|
69
|
+
const seenNames = new Set();
|
|
70
|
+
// Match PREREQ_PM => { ... } block
|
|
71
|
+
const prereqMatch = /PREREQ_PM\s*=>\s*\{([^}]*)}/s.exec(content);
|
|
72
|
+
if (!prereqMatch)
|
|
73
|
+
return [];
|
|
74
|
+
const block = prereqMatch[1] ?? "";
|
|
75
|
+
// Match 'Module::Name' => 'version' or "Module::Name" => "version"
|
|
76
|
+
const entryRegex = /['"]([^'"]+)['"]\s*=>\s*['"]?([^'",}]*?)['"]?\s*(?:,|$)/g;
|
|
77
|
+
let match;
|
|
78
|
+
while ((match = entryRegex.exec(block)) !== null) {
|
|
79
|
+
const moduleName = match[1];
|
|
80
|
+
if (moduleName === undefined)
|
|
81
|
+
continue;
|
|
82
|
+
const name = moduleToDistName(moduleName);
|
|
83
|
+
if (seenNames.has(name))
|
|
84
|
+
continue;
|
|
85
|
+
seenNames.add(name);
|
|
86
|
+
const versionSpec = match[2]?.trim();
|
|
87
|
+
const version = versionSpec !== undefined && versionSpec !== "" && /^\d+(?:\.\d+)*$/.test(versionSpec)
|
|
88
|
+
? versionSpec
|
|
89
|
+
: undefined;
|
|
90
|
+
results.push({
|
|
91
|
+
purl: {
|
|
92
|
+
type: cpanType,
|
|
93
|
+
name,
|
|
94
|
+
...(version !== undefined ? { version } : {}),
|
|
95
|
+
},
|
|
96
|
+
type: cpanType,
|
|
97
|
+
source,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return results;
|
|
101
|
+
};
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Detector
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
/**
|
|
106
|
+
* CPAN package detector.
|
|
107
|
+
*
|
|
108
|
+
* Scans `cpanfile` and `Makefile.PL` in the project directory and extracts
|
|
109
|
+
* dependencies.
|
|
110
|
+
*
|
|
111
|
+
* @experimental This API is unstable and may change without notice.
|
|
112
|
+
*/
|
|
113
|
+
export const cpanDetector = {
|
|
114
|
+
type: cpanType,
|
|
115
|
+
detect: Effect.fn("detect.cpan")(function* (projectDir) {
|
|
116
|
+
const path = yield* Path.Path;
|
|
117
|
+
const allPackages = [];
|
|
118
|
+
const seenNames = new Set();
|
|
119
|
+
const addUnique = (pkgs) => {
|
|
120
|
+
for (const pkg of pkgs) {
|
|
121
|
+
if (!seenNames.has(pkg.purl.name)) {
|
|
122
|
+
seenNames.add(pkg.purl.name);
|
|
123
|
+
allPackages.push(pkg);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
// 1. cpanfile
|
|
128
|
+
const cpanfilePath = path.join(projectDir, "cpanfile");
|
|
129
|
+
const cpanfileContent = yield* readFileOptional(cpanfilePath);
|
|
130
|
+
if (Option.isSome(cpanfileContent)) {
|
|
131
|
+
addUnique(parseCpanfile(cpanfileContent.value, cpanfilePath));
|
|
132
|
+
}
|
|
133
|
+
// 2. Makefile.PL
|
|
134
|
+
const makefilePath = path.join(projectDir, "Makefile.PL");
|
|
135
|
+
const makefileContent = yield* readFileOptional(makefilePath);
|
|
136
|
+
if (Option.isSome(makefileContent)) {
|
|
137
|
+
addUnique(parseMakefilePL(makefileContent.value, makefilePath));
|
|
138
|
+
}
|
|
139
|
+
return allPackages;
|
|
140
|
+
}, Effect.annotateLogs({ detector: "cpan" }), Effect.withSpan("detect.cpan")),
|
|
141
|
+
};
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// Reader
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
/** Schema for extracting the x_axm field from MYMETA.json. */
|
|
146
|
+
const MymetaAxmSchema = Schema.Struct({
|
|
147
|
+
x_axm: Schema.optional(Schema.Unknown),
|
|
148
|
+
});
|
|
149
|
+
const decodeMymetaAxm = Schema.decodeUnknownResult(MymetaAxmSchema);
|
|
150
|
+
/**
|
|
151
|
+
* CPAN package reader.
|
|
152
|
+
*
|
|
153
|
+
* Reads `x_axm` from `<lib-path>/.meta/<dist>/MYMETA.json` for each
|
|
154
|
+
* detected CPAN package and extracts recommendation metadata.
|
|
155
|
+
*
|
|
156
|
+
* @experimental This API is unstable and may change without notice.
|
|
157
|
+
*/
|
|
158
|
+
export const cpanReader = {
|
|
159
|
+
type: cpanType,
|
|
160
|
+
read: Effect.fn("read.cpan")(function* (pkg) {
|
|
161
|
+
const path = yield* Path.Path;
|
|
162
|
+
// Default Perl local::lib path
|
|
163
|
+
const libPath = yield* Effect.sync(() => readEnv("PERL5LIB") ?? readEnv("PERL_LOCAL_LIB_ROOT") ?? "local/lib/perl5");
|
|
164
|
+
const distName = pkg.purl.name;
|
|
165
|
+
const version = pkg.purl.version;
|
|
166
|
+
const metaDir = version !== undefined ? `${distName}-${version}` : distName;
|
|
167
|
+
const mymetaPath = path.join(libPath, ".meta", metaDir, "MYMETA.json");
|
|
168
|
+
const content = yield* readFileOptional(mymetaPath);
|
|
169
|
+
if (Option.isNone(content))
|
|
170
|
+
return Option.none();
|
|
171
|
+
const parsed = yield* parseJsonOptional(content.value, `${distName}/MYMETA.json`);
|
|
172
|
+
if (Option.isNone(parsed))
|
|
173
|
+
return Option.none();
|
|
174
|
+
// Extract x_axm metadata
|
|
175
|
+
const containerResult = decodeMymetaAxm(parsed.value);
|
|
176
|
+
if (Result.isFailure(containerResult))
|
|
177
|
+
return Option.none();
|
|
178
|
+
const axmRaw = containerResult.success.x_axm;
|
|
179
|
+
if (axmRaw === undefined)
|
|
180
|
+
return Option.none();
|
|
181
|
+
const metaResult = decodeAxmMeta(axmRaw);
|
|
182
|
+
if (Result.isFailure(metaResult)) {
|
|
183
|
+
yield* Effect.logWarning(`Invalid axm metadata in ${distName}: schema validation failed`);
|
|
184
|
+
return Option.none();
|
|
185
|
+
}
|
|
186
|
+
return Option.some(metaResult.success.extensions);
|
|
187
|
+
}, Effect.annotateLogs({ reader: "cpan" }), Effect.withSpan("read.cpan")),
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=cpan.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRAN (R) package detector and reader for package-compatibility discovery.
|
|
3
|
+
*
|
|
4
|
+
* Parses `DESCRIPTION` files for `Depends`, `Imports`, and `Suggests` fields.
|
|
5
|
+
* Reads `Config/axm` prefixed fields from installed package DESCRIPTION files.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import type { PackageDetector, PackageReader } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* CRAN package detector.
|
|
13
|
+
*
|
|
14
|
+
* Scans `DESCRIPTION` file in the project directory and extracts dependencies
|
|
15
|
+
* from `Depends`, `Imports`, and `Suggests` fields.
|
|
16
|
+
*
|
|
17
|
+
* @experimental This API is unstable and may change without notice.
|
|
18
|
+
*/
|
|
19
|
+
export declare const cranDetector: PackageDetector;
|
|
20
|
+
/**
|
|
21
|
+
* CRAN package reader.
|
|
22
|
+
*
|
|
23
|
+
* Reads `Config/axm` prefixed fields from `<lib-path>/<pkg>/DESCRIPTION`
|
|
24
|
+
* for each detected CRAN package and extracts recommendation metadata.
|
|
25
|
+
*
|
|
26
|
+
* @experimental This API is unstable and may change without notice.
|
|
27
|
+
*/
|
|
28
|
+
export declare const cranReader: PackageReader;
|
|
29
|
+
//# sourceMappingURL=cran.d.ts.map
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRAN (R) package detector and reader for package-compatibility discovery.
|
|
3
|
+
*
|
|
4
|
+
* Parses `DESCRIPTION` files for `Depends`, `Imports`, and `Suggests` fields.
|
|
5
|
+
* Reads `Config/axm` prefixed fields from installed package DESCRIPTION files.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
// Intentional escape hatch: node:os homedir() has no @effect/platform equivalent.
|
|
11
|
+
import * as os from "node:os";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import * as Path from "effect/Path";
|
|
15
|
+
import * as Result from "effect/Result";
|
|
16
|
+
import * as Schema from "effect/Schema";
|
|
17
|
+
import { readEnv } from "../internal/environment.js";
|
|
18
|
+
import { PackageTypeSchema } from "@agentxm/extension-model/unstable/packaging/package-type";
|
|
19
|
+
import { decodeAxmMeta, readFileOptional } from "./reader-io.js";
|
|
20
|
+
const cranType = Schema.decodeUnknownSync(PackageTypeSchema)("cran");
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Helpers
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/**
|
|
25
|
+
* Parse a DESCRIPTION file into a key-value map.
|
|
26
|
+
* Handles continuation lines (lines starting with whitespace are appended
|
|
27
|
+
* to the previous field value).
|
|
28
|
+
*/
|
|
29
|
+
const parseDescriptionFile = (content) => {
|
|
30
|
+
const result = {};
|
|
31
|
+
let currentKey;
|
|
32
|
+
for (const line of content.split("\n")) {
|
|
33
|
+
// Continuation line: starts with whitespace
|
|
34
|
+
if (/^\s/.test(line) && currentKey !== undefined) {
|
|
35
|
+
const existing = result[currentKey];
|
|
36
|
+
if (existing !== undefined) {
|
|
37
|
+
result[currentKey] = existing + " " + line.trim();
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// New field: Key: Value
|
|
42
|
+
const colonIdx = line.indexOf(":");
|
|
43
|
+
if (colonIdx > 0) {
|
|
44
|
+
currentKey = line.slice(0, colonIdx).trim();
|
|
45
|
+
result[currentKey] = line.slice(colonIdx + 1).trim();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Parse a comma-separated list of R package dependencies.
|
|
52
|
+
* Each entry is like "name (>= version)" or just "name".
|
|
53
|
+
* Filters out base R packages like "R" itself.
|
|
54
|
+
*/
|
|
55
|
+
const parseDependencyList = (value, source) => {
|
|
56
|
+
const results = [];
|
|
57
|
+
for (const entry of value.split(",")) {
|
|
58
|
+
const trimmed = entry.trim();
|
|
59
|
+
if (trimmed === "")
|
|
60
|
+
continue;
|
|
61
|
+
// Parse "name (>= version)" or "name"
|
|
62
|
+
const match = /^([A-Za-z][A-Za-z0-9.]*)(?:\s*\((.+)\))?$/.exec(trimmed);
|
|
63
|
+
if (!match)
|
|
64
|
+
continue;
|
|
65
|
+
const name = match[1];
|
|
66
|
+
if (name === undefined || name === "R")
|
|
67
|
+
continue;
|
|
68
|
+
// Only extract exact version constraints
|
|
69
|
+
const constraint = match[2]?.trim();
|
|
70
|
+
let version;
|
|
71
|
+
if (constraint !== undefined) {
|
|
72
|
+
const exactMatch = /^==\s*(.+)$/.exec(constraint);
|
|
73
|
+
if (exactMatch) {
|
|
74
|
+
version = exactMatch[1]?.trim();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
results.push({
|
|
78
|
+
purl: {
|
|
79
|
+
type: cranType,
|
|
80
|
+
name,
|
|
81
|
+
...(version !== undefined ? { version } : {}),
|
|
82
|
+
},
|
|
83
|
+
type: cranType,
|
|
84
|
+
source,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return results;
|
|
88
|
+
};
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Detector
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
/**
|
|
93
|
+
* CRAN package detector.
|
|
94
|
+
*
|
|
95
|
+
* Scans `DESCRIPTION` file in the project directory and extracts dependencies
|
|
96
|
+
* from `Depends`, `Imports`, and `Suggests` fields.
|
|
97
|
+
*
|
|
98
|
+
* @experimental This API is unstable and may change without notice.
|
|
99
|
+
*/
|
|
100
|
+
export const cranDetector = {
|
|
101
|
+
type: cranType,
|
|
102
|
+
detect: Effect.fn("detect.cran")(function* (projectDir) {
|
|
103
|
+
const path = yield* Path.Path;
|
|
104
|
+
const descriptionPath = path.join(projectDir, "DESCRIPTION");
|
|
105
|
+
const content = yield* readFileOptional(descriptionPath);
|
|
106
|
+
if (Option.isNone(content))
|
|
107
|
+
return [];
|
|
108
|
+
const fields = parseDescriptionFile(content.value);
|
|
109
|
+
const allPackages = [];
|
|
110
|
+
const seenNames = new Set();
|
|
111
|
+
const addUnique = (pkgs) => {
|
|
112
|
+
for (const pkg of pkgs) {
|
|
113
|
+
if (!seenNames.has(pkg.purl.name)) {
|
|
114
|
+
seenNames.add(pkg.purl.name);
|
|
115
|
+
allPackages.push(pkg);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
// Extract from Depends, Imports, Suggests
|
|
120
|
+
for (const field of ["Depends", "Imports", "Suggests"]) {
|
|
121
|
+
const value = fields[field];
|
|
122
|
+
if (value !== undefined) {
|
|
123
|
+
addUnique(parseDependencyList(value, descriptionPath));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return allPackages;
|
|
127
|
+
}, Effect.annotateLogs({ detector: "cran" }), Effect.withSpan("detect.cran")),
|
|
128
|
+
};
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Reader
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
/**
|
|
133
|
+
* Resolve the R library path.
|
|
134
|
+
* Checks R_LIBS_USER, then defaults to ~/R/library.
|
|
135
|
+
*/
|
|
136
|
+
const resolveRLibPath = () => Effect.sync(() => readEnv("R_LIBS_USER") ?? `${os.homedir()}/R/library`);
|
|
137
|
+
/**
|
|
138
|
+
* CRAN package reader.
|
|
139
|
+
*
|
|
140
|
+
* Reads `Config/axm` prefixed fields from `<lib-path>/<pkg>/DESCRIPTION`
|
|
141
|
+
* for each detected CRAN package and extracts recommendation metadata.
|
|
142
|
+
*
|
|
143
|
+
* @experimental This API is unstable and may change without notice.
|
|
144
|
+
*/
|
|
145
|
+
export const cranReader = {
|
|
146
|
+
type: cranType,
|
|
147
|
+
read: Effect.fn("read.cran")(function* (pkg) {
|
|
148
|
+
const path = yield* Path.Path;
|
|
149
|
+
const libPath = yield* resolveRLibPath();
|
|
150
|
+
const descriptionPath = path.join(libPath, pkg.purl.name, "DESCRIPTION");
|
|
151
|
+
const content = yield* readFileOptional(descriptionPath);
|
|
152
|
+
if (Option.isNone(content))
|
|
153
|
+
return Option.none();
|
|
154
|
+
const fields = parseDescriptionFile(content.value);
|
|
155
|
+
// Look for Config/axm fields - the metadata is stored as JSON in Config/axm
|
|
156
|
+
const axmField = fields["Config/axm"];
|
|
157
|
+
if (axmField === undefined)
|
|
158
|
+
return Option.none();
|
|
159
|
+
// Parse the axm metadata JSON
|
|
160
|
+
const axmParsed = yield* Effect.try({
|
|
161
|
+
try: () => JSON.parse(axmField),
|
|
162
|
+
catch: () => ({ _tag: "JsonParseError" }),
|
|
163
|
+
}).pipe(Effect.option);
|
|
164
|
+
if (Option.isNone(axmParsed)) {
|
|
165
|
+
yield* Effect.logWarning(`Malformed Config/axm in ${pkg.purl.name}: invalid JSON`);
|
|
166
|
+
return Option.none();
|
|
167
|
+
}
|
|
168
|
+
const metaResult = decodeAxmMeta(axmParsed.value);
|
|
169
|
+
if (Result.isFailure(metaResult)) {
|
|
170
|
+
yield* Effect.logWarning(`Invalid axm metadata in ${pkg.purl.name}: schema validation failed`);
|
|
171
|
+
return Option.none();
|
|
172
|
+
}
|
|
173
|
+
return Option.some(metaResult.success.extensions);
|
|
174
|
+
}, Effect.annotateLogs({ reader: "cran" }), Effect.withSpan("read.cran")),
|
|
175
|
+
};
|
|
176
|
+
//# sourceMappingURL=cran.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect orchestrator: runs all package detectors concurrently,
|
|
3
|
+
* flattens results, and deduplicates by purl equivalence.
|
|
4
|
+
*
|
|
5
|
+
* @experimental This API is unstable and may change without notice.
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import type { PackageDetector } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Run all detectors concurrently, flatten and deduplicate results.
|
|
12
|
+
*
|
|
13
|
+
* @experimental This API is unstable and may change without notice.
|
|
14
|
+
*/
|
|
15
|
+
export declare const detectPackages: (projectDir: string, detectors: readonly PackageDetector[]) => Effect.Effect<import("./types.js").DetectedPackage[], never, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
16
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect orchestrator: runs all package detectors concurrently,
|
|
3
|
+
* flattens results, and deduplicates by purl equivalence.
|
|
4
|
+
*
|
|
5
|
+
* @experimental This API is unstable and may change without notice.
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import * as Array from "effect/Array";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Schema from "effect/Schema";
|
|
11
|
+
import { PackageUrlPartsSchema } from "@agentxm/extension-model/unstable/packaging/package-url";
|
|
12
|
+
const purlEquivalence = Schema.toEquivalence(PackageUrlPartsSchema);
|
|
13
|
+
/**
|
|
14
|
+
* Run all detectors concurrently, flatten and deduplicate results.
|
|
15
|
+
*
|
|
16
|
+
* @experimental This API is unstable and may change without notice.
|
|
17
|
+
*/
|
|
18
|
+
export const detectPackages = Effect.fn("discover.detect")(function* (projectDir, detectors) {
|
|
19
|
+
const results = yield* Effect.forEach(detectors, (d) => d.detect(projectDir), {
|
|
20
|
+
concurrency: "unbounded",
|
|
21
|
+
});
|
|
22
|
+
const allDetected = Array.flatten(results);
|
|
23
|
+
return Array.dedupeWith(allDetected, (a, b) => purlEquivalence(a.purl, b.purl));
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as Option from "effect/Option";
|
|
2
|
+
import type { PackageType } from "@agentxm/extension-model/unstable/packaging/package-type";
|
|
3
|
+
import type { DetectedPackage } from "./types.js";
|
|
4
|
+
interface DetectedPackageInput {
|
|
5
|
+
readonly type: PackageType;
|
|
6
|
+
readonly namespace?: string;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly version?: string;
|
|
9
|
+
readonly source: string;
|
|
10
|
+
}
|
|
11
|
+
/** Builds a package identity without allowing malformed manifests to throw. */
|
|
12
|
+
export declare const makeDetectedPackage: (input: DetectedPackageInput) => Option.Option<DetectedPackage>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=detected-package.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as Option from "effect/Option";
|
|
2
|
+
import { PackageURL } from "packageurl-js";
|
|
3
|
+
import { decodePurl } from "./reader-io.js";
|
|
4
|
+
/** Builds a package identity without allowing malformed manifests to throw. */
|
|
5
|
+
export const makeDetectedPackage = (input) => {
|
|
6
|
+
if (input.name.trim() === "")
|
|
7
|
+
return Option.none();
|
|
8
|
+
try {
|
|
9
|
+
const purl = new PackageURL(input.type, input.namespace === undefined || input.namespace === "" ? null : input.namespace, input.name, input.version ?? null, null, null);
|
|
10
|
+
return Option.some({
|
|
11
|
+
purl: decodePurl(purl.toString()),
|
|
12
|
+
type: input.type,
|
|
13
|
+
source: input.source,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return Option.none();
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=detected-package.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docker image detector and reader for package-compatibility discovery.
|
|
3
|
+
*
|
|
4
|
+
* @experimental This API is unstable and may change without notice.
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
import type { PackageDetector, PackageReader } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Docker package detector.
|
|
10
|
+
*
|
|
11
|
+
* Scans `Dockerfile`, `docker-compose.yml`, and `docker-compose.yaml`
|
|
12
|
+
* for image dependencies.
|
|
13
|
+
*
|
|
14
|
+
* @experimental This API is unstable and may change without notice.
|
|
15
|
+
*/
|
|
16
|
+
export declare const dockerDetector: PackageDetector;
|
|
17
|
+
/**
|
|
18
|
+
* Docker package reader.
|
|
19
|
+
*
|
|
20
|
+
* Inspects local Docker image metadata for `sh.axm.recommended-extensions`
|
|
21
|
+
* annotation. Since inspecting Docker images requires the Docker CLI,
|
|
22
|
+
* this reader returns Option.none when Docker is not available.
|
|
23
|
+
*
|
|
24
|
+
* @experimental This API is unstable and may change without notice.
|
|
25
|
+
*/
|
|
26
|
+
export declare const dockerReader: PackageReader;
|
|
27
|
+
//# sourceMappingURL=docker.d.ts.map
|