@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.
Files changed (72) hide show
  1. package/LICENSE +110 -0
  2. package/dist/src/discover.d.ts +34 -0
  3. package/dist/src/discover.js +133 -0
  4. package/dist/src/index.d.ts +13 -0
  5. package/dist/src/index.js +12 -0
  6. package/dist/src/internal/environment.d.ts +14 -0
  7. package/dist/src/internal/environment.js +15 -0
  8. package/dist/src/packaging/bazel.d.ts +27 -0
  9. package/dist/src/packaging/bazel.js +125 -0
  10. package/dist/src/packaging/cargo.d.ts +32 -0
  11. package/dist/src/packaging/cargo.js +270 -0
  12. package/dist/src/packaging/cocoapods.d.ts +26 -0
  13. package/dist/src/packaging/cocoapods.js +187 -0
  14. package/dist/src/packaging/composer.d.ts +26 -0
  15. package/dist/src/packaging/composer.js +144 -0
  16. package/dist/src/packaging/conan.d.ts +30 -0
  17. package/dist/src/packaging/conan.js +238 -0
  18. package/dist/src/packaging/conda.d.ts +26 -0
  19. package/dist/src/packaging/conda.js +320 -0
  20. package/dist/src/packaging/cpan.d.ts +29 -0
  21. package/dist/src/packaging/cpan.js +189 -0
  22. package/dist/src/packaging/cran.d.ts +29 -0
  23. package/dist/src/packaging/cran.js +176 -0
  24. package/dist/src/packaging/detect.d.ts +16 -0
  25. package/dist/src/packaging/detect.js +25 -0
  26. package/dist/src/packaging/detected-package.d.ts +14 -0
  27. package/dist/src/packaging/detected-package.js +20 -0
  28. package/dist/src/packaging/docker.d.ts +27 -0
  29. package/dist/src/packaging/docker.js +256 -0
  30. package/dist/src/packaging/gem.d.ts +26 -0
  31. package/dist/src/packaging/gem.js +234 -0
  32. package/dist/src/packaging/golang.d.ts +26 -0
  33. package/dist/src/packaging/golang.js +169 -0
  34. package/dist/src/packaging/hackage.d.ts +26 -0
  35. package/dist/src/packaging/hackage.js +305 -0
  36. package/dist/src/packaging/hex.d.ts +28 -0
  37. package/dist/src/packaging/hex.js +186 -0
  38. package/dist/src/packaging/huggingface.d.ts +20 -0
  39. package/dist/src/packaging/huggingface.js +112 -0
  40. package/dist/src/packaging/index.d.ts +44 -0
  41. package/dist/src/packaging/index.js +120 -0
  42. package/dist/src/packaging/jsr.d.ts +30 -0
  43. package/dist/src/packaging/jsr.js +227 -0
  44. package/dist/src/packaging/julia.d.ts +27 -0
  45. package/dist/src/packaging/julia.js +165 -0
  46. package/dist/src/packaging/luarocks.d.ts +28 -0
  47. package/dist/src/packaging/luarocks.js +159 -0
  48. package/dist/src/packaging/maven.d.ts +27 -0
  49. package/dist/src/packaging/maven.js +471 -0
  50. package/dist/src/packaging/mojo.d.ts +29 -0
  51. package/dist/src/packaging/mojo.js +148 -0
  52. package/dist/src/packaging/npm.d.ts +26 -0
  53. package/dist/src/packaging/npm.js +190 -0
  54. package/dist/src/packaging/nuget.d.ts +26 -0
  55. package/dist/src/packaging/nuget.js +240 -0
  56. package/dist/src/packaging/opam.d.ts +27 -0
  57. package/dist/src/packaging/opam.js +287 -0
  58. package/dist/src/packaging/pub.d.ts +26 -0
  59. package/dist/src/packaging/pub.js +357 -0
  60. package/dist/src/packaging/pypi.d.ts +23 -0
  61. package/dist/src/packaging/pypi.js +448 -0
  62. package/dist/src/packaging/read.d.ts +20 -0
  63. package/dist/src/packaging/read.js +31 -0
  64. package/dist/src/packaging/reader-io.d.ts +29 -0
  65. package/dist/src/packaging/reader-io.js +29 -0
  66. package/dist/src/packaging/swift.d.ts +26 -0
  67. package/dist/src/packaging/swift.js +141 -0
  68. package/dist/src/packaging/types.d.ts +43 -0
  69. package/dist/src/packaging/types.js +8 -0
  70. package/dist/src/packaging/zig.d.ts +32 -0
  71. package/dist/src/packaging/zig.js +151 -0
  72. 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