@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,227 @@
1
+ /**
2
+ * JSR package detector and Deno reader for package-compatibility discovery.
3
+ *
4
+ * Parses `deno.json`/`deno.jsonc` for `jsr:@scope/name` imports and reads
5
+ * axm metadata from Deno's module cache.
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 FileSystem from "effect/FileSystem";
14
+ import * as Option from "effect/Option";
15
+ import * as Path from "effect/Path";
16
+ import * as Result from "effect/Result";
17
+ import * as Schema from "effect/Schema";
18
+ import { PackageURL } from "packageurl-js";
19
+ import { readEnv } from "../internal/environment.js";
20
+ import { PackageTypeSchema } from "@agentxm/extension-model/unstable/packaging/package-type";
21
+ import { decodeAxmMeta, decodePurl, parseJsonOptional, readFileOptional } from "./reader-io.js";
22
+ const jsrType = Schema.decodeUnknownSync(PackageTypeSchema)("jsr");
23
+ /**
24
+ * Strip single-line (//) and multi-line comments from JSONC content.
25
+ * Simple approach that handles most common cases.
26
+ */
27
+ const stripJsoncComments = (content) => {
28
+ let result = "";
29
+ let i = 0;
30
+ let inString = false;
31
+ while (i < content.length) {
32
+ // Track string boundaries
33
+ if (content[i] === '"' && (i === 0 || content[i - 1] !== "\\")) {
34
+ inString = !inString;
35
+ result += content[i];
36
+ i++;
37
+ continue;
38
+ }
39
+ if (inString) {
40
+ result += content[i];
41
+ i++;
42
+ continue;
43
+ }
44
+ // Single-line comment
45
+ if (content[i] === "/" && content[i + 1] === "/") {
46
+ while (i < content.length && content[i] !== "\n")
47
+ i++;
48
+ continue;
49
+ }
50
+ // Multi-line comment
51
+ if (content[i] === "/" && content[i + 1] === "*") {
52
+ i += 2;
53
+ while (i < content.length - 1 && !(content[i] === "*" && content[i + 1] === "/"))
54
+ i++;
55
+ i += 2; // skip */
56
+ continue;
57
+ }
58
+ result += content[i];
59
+ i++;
60
+ }
61
+ return result;
62
+ };
63
+ /**
64
+ * Returns true if the specifier is an exact semver version (no range operators).
65
+ */
66
+ const isExactVersion = (version) => /^\d+\.\d+\.\d+(?:[-+][a-zA-Z0-9._+-]*)?$/.test(version);
67
+ /**
68
+ * Parse a JSR import specifier like `jsr:@scope/name@version`.
69
+ * Returns parsed parts or undefined if not a JSR import.
70
+ */
71
+ const parseJsrSpecifier = (specifier) => {
72
+ if (!specifier.startsWith("jsr:"))
73
+ return undefined;
74
+ const rest = specifier.slice(4); // Remove "jsr:" prefix
75
+ // Match @scope/name or @scope/name@version
76
+ const match = /^(@[^/]+)\/([^@]+)(?:@(.+))?$/.exec(rest);
77
+ if (match === null || match[1] === undefined || match[2] === undefined)
78
+ return undefined;
79
+ return {
80
+ scope: match[1],
81
+ name: match[2],
82
+ ...(match[3] !== undefined ? { version: match[3] } : {}),
83
+ };
84
+ };
85
+ /**
86
+ * Extract JSR imports from a parsed deno.json imports map.
87
+ */
88
+ const extractJsrImports = (imports, source) => {
89
+ const results = [];
90
+ for (const specifier of Object.values(imports)) {
91
+ const parsed = parseJsrSpecifier(specifier);
92
+ if (parsed === undefined)
93
+ continue; // Skip non-JSR imports (npm:, etc.)
94
+ const version = parsed.version !== undefined && isExactVersion(parsed.version) ? parsed.version : undefined;
95
+ const purl = new PackageURL("jsr", parsed.scope, parsed.name, version ?? null, null, null);
96
+ const purlParts = decodePurl(purl.toString());
97
+ results.push({ purl: purlParts, type: jsrType, source });
98
+ }
99
+ return results;
100
+ };
101
+ /** Schema to extract the optional "imports" field from deno.json. */
102
+ const DenoImportsSchema = Schema.Struct({
103
+ imports: Schema.optional(Schema.Record(Schema.String, Schema.String)),
104
+ });
105
+ const decodeDenoImports = Schema.decodeUnknownResult(DenoImportsSchema);
106
+ /**
107
+ * JSR package detector.
108
+ *
109
+ * Scans `deno.json` and `deno.jsonc` in the project directory and extracts
110
+ * `jsr:@scope/name` imports, producing `pkg:jsr/<scope>/<name>` purls.
111
+ * npm-prefixed imports are skipped.
112
+ *
113
+ * @experimental This API is unstable and may change without notice.
114
+ */
115
+ export const jsrDetector = {
116
+ type: jsrType,
117
+ detect: Effect.fn("detect.jsr")(function* (projectDir) {
118
+ const path = yield* Path.Path;
119
+ // Try deno.json first, then deno.jsonc
120
+ const denoJsonPath = path.join(projectDir, "deno.json");
121
+ const denoJsoncPath = path.join(projectDir, "deno.jsonc");
122
+ let content = yield* readFileOptional(denoJsonPath);
123
+ let source = denoJsonPath;
124
+ let isJsonc = false;
125
+ if (Option.isNone(content)) {
126
+ content = yield* readFileOptional(denoJsoncPath);
127
+ source = denoJsoncPath;
128
+ isJsonc = true;
129
+ }
130
+ if (Option.isNone(content))
131
+ return [];
132
+ // Strip comments for .jsonc files
133
+ const jsonContent = isJsonc ? stripJsoncComments(content.value) : content.value;
134
+ const parsed = yield* parseJsonOptional(jsonContent, source);
135
+ if (Option.isNone(parsed))
136
+ return [];
137
+ const importsResult = decodeDenoImports(parsed.value);
138
+ if (Result.isFailure(importsResult))
139
+ return [];
140
+ const imports = importsResult.success.imports;
141
+ if (imports === undefined)
142
+ return [];
143
+ return extractJsrImports(imports, source);
144
+ }, Effect.annotateLogs({ detector: "jsr" }), Effect.withSpan("detect.jsr")),
145
+ };
146
+ /** Schema to extract the optional "axm" field from deno.json. */
147
+ const AxmContainerSchema = Schema.Struct({
148
+ axm: Schema.optional(Schema.Unknown),
149
+ });
150
+ const decodeAxmContainer = Schema.decodeUnknownResult(AxmContainerSchema);
151
+ /**
152
+ * Resolve the Deno cache directory.
153
+ * Uses $DENO_DIR if set, otherwise platform-specific defaults.
154
+ */
155
+ const resolveDenoDir = () => Effect.sync(() => {
156
+ const denoDir = readEnv("DENO_DIR");
157
+ if (denoDir !== undefined && denoDir !== "")
158
+ return denoDir;
159
+ // Platform-specific defaults
160
+ if (process.platform === "darwin") {
161
+ return `${os.homedir()}/Library/Caches/deno`;
162
+ }
163
+ return `${os.homedir()}/.cache/deno`;
164
+ });
165
+ /**
166
+ * Deno package reader.
167
+ *
168
+ * Reads axm metadata from cached module metadata in Deno's module cache.
169
+ * Checks for an `"axm"` field in cached `deno.json` files.
170
+ *
171
+ * @experimental This API is unstable and may change without notice.
172
+ */
173
+ export const denoReader = {
174
+ type: jsrType,
175
+ read: Effect.fn("read.deno")(function* (pkg) {
176
+ const path = yield* Path.Path;
177
+ const fs = yield* FileSystem.FileSystem;
178
+ const denoDir = yield* resolveDenoDir();
179
+ // Check if deno cache directory exists
180
+ const denoDirExists = yield* fs.exists(denoDir).pipe(Effect.option);
181
+ if (Option.isNone(denoDirExists) || !denoDirExists.value)
182
+ return Option.none();
183
+ const pkgNamespace = pkg.purl.namespace;
184
+ if (pkgNamespace === undefined)
185
+ return Option.none();
186
+ const scope = pkgNamespace;
187
+ // Look for cached module metadata
188
+ // Deno caches JSR packages in registry cache
189
+ const registryCacheDir = path.join(denoDir, "registries", "jsr.io");
190
+ const cacheDirExists = yield* fs.exists(registryCacheDir).pipe(Effect.option);
191
+ if (Option.isNone(cacheDirExists) || !cacheDirExists.value)
192
+ return Option.none();
193
+ // Check the cached package directory for deno.json with axm field
194
+ const pkgCacheDir = path.join(registryCacheDir, scope, pkg.purl.name);
195
+ const pkgDirExists = yield* fs.exists(pkgCacheDir).pipe(Effect.option);
196
+ if (Option.isNone(pkgDirExists) || !pkgDirExists.value)
197
+ return Option.none();
198
+ // Scan version directories for deno.json with axm field
199
+ const versionDirs = yield* fs.readDirectory(pkgCacheDir).pipe(Effect.option);
200
+ if (Option.isNone(versionDirs))
201
+ return Option.none();
202
+ for (const versionDir of versionDirs.value) {
203
+ const denoJsonPath = path.join(pkgCacheDir, versionDir, "deno.json");
204
+ const content = yield* readFileOptional(denoJsonPath);
205
+ if (Option.isNone(content))
206
+ continue;
207
+ const parsed = yield* parseJsonOptional(content.value, `${scope}/${pkg.purl.name}/deno.json`);
208
+ if (Option.isNone(parsed))
209
+ continue;
210
+ // Extract and validate the "axm" field
211
+ const axmContainerResult = decodeAxmContainer(parsed.value);
212
+ if (Result.isFailure(axmContainerResult))
213
+ continue;
214
+ const axmRaw = axmContainerResult.success.axm;
215
+ if (axmRaw === undefined)
216
+ continue;
217
+ const metaResult = decodeAxmMeta(axmRaw);
218
+ if (Result.isFailure(metaResult)) {
219
+ yield* Effect.logWarning(`Invalid axm metadata in deno cache for ${scope}/${pkg.purl.name}: schema validation failed`);
220
+ continue;
221
+ }
222
+ return Option.some(metaResult.success.extensions);
223
+ }
224
+ return Option.none();
225
+ }, Effect.annotateLogs({ reader: "deno" }), Effect.withSpan("read.deno")),
226
+ };
227
+ //# sourceMappingURL=jsr.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Julia package 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
+ * Julia package detector.
10
+ *
11
+ * Scans `Project.toml` in the project directory and extracts dependencies
12
+ * from the `[deps]` section. All purls are versionless since Julia
13
+ * identifies packages by UUID.
14
+ *
15
+ * @experimental This API is unstable and may change without notice.
16
+ */
17
+ export declare const juliaDetector: PackageDetector;
18
+ /**
19
+ * Julia package reader.
20
+ *
21
+ * Reads `[axm]` section from `~/.julia/packages/<pkg>/<hash>/Project.toml`
22
+ * for each detected Julia package.
23
+ *
24
+ * @experimental This API is unstable and may change without notice.
25
+ */
26
+ export declare const juliaReader: PackageReader;
27
+ //# sourceMappingURL=julia.d.ts.map
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Julia package detector and reader for package-compatibility discovery.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ * @packageDocumentation
6
+ */
7
+ // Intentional escape hatch: node:os homedir() has no @effect/platform equivalent.
8
+ import * as os from "node:os";
9
+ import * as Effect from "effect/Effect";
10
+ import * as FileSystem from "effect/FileSystem";
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 { PackageURL } from "packageurl-js";
16
+ import { parseTomlValue } from "@agentxm/extension-workspace";
17
+ import { PackageTypeSchema } from "@agentxm/extension-model/unstable/packaging/package-type";
18
+ import { decodeAxmMeta, decodePurl, readFileOptional } from "./reader-io.js";
19
+ const juliaType = Schema.decodeUnknownSync(PackageTypeSchema)("julia");
20
+ /** UUID pattern for Julia dependency values. */
21
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
22
+ /**
23
+ * Parse a simple TOML [deps] section from Project.toml content.
24
+ * Julia's Project.toml uses TOML format with [deps] section containing:
25
+ * PackageName = "uuid-string"
26
+ */
27
+ const parseDepsSection = (content, source) => {
28
+ const results = [];
29
+ const lines = content.split("\n");
30
+ let inDepsSection = false;
31
+ for (const line of lines) {
32
+ const trimmed = line.trim();
33
+ // Section headers
34
+ if (trimmed.startsWith("[")) {
35
+ inDepsSection = trimmed === "[deps]";
36
+ continue;
37
+ }
38
+ if (!inDepsSection)
39
+ continue;
40
+ // Skip empty lines and comments
41
+ if (trimmed === "" || trimmed.startsWith("#"))
42
+ continue;
43
+ // Parse key = "value" entries
44
+ const match = /^(\S+)\s*=\s*"([^"]*)"/.exec(trimmed);
45
+ if (match === null)
46
+ continue;
47
+ const name = match[1];
48
+ const value = match[2];
49
+ if (name === undefined || value === undefined)
50
+ continue;
51
+ // Validate it looks like a UUID
52
+ if (!UUID_PATTERN.test(value))
53
+ continue;
54
+ // Julia deps are always versionless (identified by UUID)
55
+ const purl = new PackageURL("julia", null, name, null, null, null);
56
+ const purlParts = decodePurl(purl.toString());
57
+ results.push({ purl: purlParts, type: juliaType, source });
58
+ }
59
+ return results;
60
+ };
61
+ /**
62
+ * Julia package detector.
63
+ *
64
+ * Scans `Project.toml` in the project directory and extracts dependencies
65
+ * from the `[deps]` section. All purls are versionless since Julia
66
+ * identifies packages by UUID.
67
+ *
68
+ * @experimental This API is unstable and may change without notice.
69
+ */
70
+ export const juliaDetector = {
71
+ type: juliaType,
72
+ detect: Effect.fn("detect.julia")(function* (projectDir) {
73
+ const path = yield* Path.Path;
74
+ const projectTomlPath = path.join(projectDir, "Project.toml");
75
+ const content = yield* readFileOptional(projectTomlPath);
76
+ if (Option.isNone(content))
77
+ return [];
78
+ const deps = parseDepsSection(content.value, projectTomlPath);
79
+ if (deps.length === 0 && content.value.trim().length > 0) {
80
+ // Content exists but no deps found - check if it looks like valid TOML
81
+ if (!content.value.includes("=") && !content.value.includes("[")) {
82
+ yield* Effect.logWarning("Malformed Project.toml, skipping");
83
+ }
84
+ }
85
+ return deps;
86
+ }, Effect.annotateLogs({ detector: "julia" }), Effect.withSpan("detect.julia")),
87
+ };
88
+ /**
89
+ * Parse a simple TOML [axm] section from Project.toml content.
90
+ * Returns the parsed fields as a record, or undefined if no [axm] section found.
91
+ */
92
+ const parseAxmSection = (content) => {
93
+ const lines = content.split("\n");
94
+ let inAxmSection = false;
95
+ const fields = {};
96
+ let foundSection = false;
97
+ for (const line of lines) {
98
+ const trimmed = line.trim();
99
+ // Section headers
100
+ if (trimmed.startsWith("[")) {
101
+ if (inAxmSection)
102
+ break; // End of [axm] section
103
+ inAxmSection = trimmed === "[axm]";
104
+ if (inAxmSection)
105
+ foundSection = true;
106
+ continue;
107
+ }
108
+ if (!inAxmSection)
109
+ continue;
110
+ // Skip empty lines and comments
111
+ if (trimmed === "" || trimmed.startsWith("#"))
112
+ continue;
113
+ // Parse key = value entries
114
+ const match = /^(\S+)\s*=\s*(.+)$/.exec(trimmed);
115
+ if (match === null)
116
+ continue;
117
+ const key = match[1];
118
+ const rawValue = match[2]?.trim();
119
+ if (key === undefined || rawValue === undefined)
120
+ continue;
121
+ // Parse TOML values
122
+ fields[key] = parseTomlValue(rawValue);
123
+ }
124
+ return foundSection ? fields : undefined;
125
+ };
126
+ /**
127
+ * Julia package reader.
128
+ *
129
+ * Reads `[axm]` section from `~/.julia/packages/<pkg>/<hash>/Project.toml`
130
+ * for each detected Julia package.
131
+ *
132
+ * @experimental This API is unstable and may change without notice.
133
+ */
134
+ export const juliaReader = {
135
+ type: juliaType,
136
+ read: Effect.fn("read.julia")(function* (pkg) {
137
+ const path = yield* Path.Path;
138
+ const fs = yield* FileSystem.FileSystem;
139
+ const pkgName = pkg.purl.name;
140
+ const home = os.homedir();
141
+ const juliaPkgsDir = path.join(home, ".julia", "packages", pkgName);
142
+ // Scan hash directories
143
+ const hashDirs = yield* fs.readDirectory(juliaPkgsDir).pipe(Effect.option);
144
+ if (Option.isNone(hashDirs))
145
+ return Option.none();
146
+ // Check each hash directory for Project.toml with [axm] section
147
+ for (const hashDir of hashDirs.value) {
148
+ const projectTomlPath = path.join(juliaPkgsDir, hashDir, "Project.toml");
149
+ const content = yield* readFileOptional(projectTomlPath);
150
+ if (Option.isNone(content))
151
+ continue;
152
+ const axmFields = parseAxmSection(content.value);
153
+ if (axmFields === undefined)
154
+ continue;
155
+ const metaResult = decodeAxmMeta(axmFields);
156
+ if (Result.isFailure(metaResult)) {
157
+ yield* Effect.logWarning(`Invalid axm metadata in ${pkgName}: schema validation failed`);
158
+ return Option.none();
159
+ }
160
+ return Option.some(metaResult.success.extensions);
161
+ }
162
+ return Option.none();
163
+ }, Effect.annotateLogs({ reader: "julia" }), Effect.withSpan("read.julia")),
164
+ };
165
+ //# sourceMappingURL=julia.js.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * LuaRocks package 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
+ * LuaRocks package detector.
10
+ *
11
+ * Scans `*.rockspec` files in the project directory and extracts
12
+ * dependencies from the `dependencies` table. Skips the `lua` runtime.
13
+ * Multiple rockspec files are processed and results deduplicated.
14
+ *
15
+ * @experimental This API is unstable and may change without notice.
16
+ */
17
+ export declare const luarocksDetector: PackageDetector;
18
+ /**
19
+ * LuaRocks package reader.
20
+ *
21
+ * Reads `axm/axm.json` sidecar from the LuaRocks install tree.
22
+ * Checks system tree (`/usr/local/lib/luarocks/rocks-5.x/`) and
23
+ * user tree (`~/.luarocks/lib/luarocks/rocks-5.x/`).
24
+ *
25
+ * @experimental This API is unstable and may change without notice.
26
+ */
27
+ export declare const luarocksReader: PackageReader;
28
+ //# sourceMappingURL=luarocks.d.ts.map
@@ -0,0 +1,159 @@
1
+ /**
2
+ * LuaRocks package detector and reader for package-compatibility discovery.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ * @packageDocumentation
6
+ */
7
+ // Intentional escape hatch: node:os homedir() has no @effect/platform equivalent.
8
+ import * as os from "node:os";
9
+ import * as Effect from "effect/Effect";
10
+ import * as FileSystem from "effect/FileSystem";
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 { PackageURL } from "packageurl-js";
16
+ import { PackageTypeSchema } from "@agentxm/extension-model/unstable/packaging/package-type";
17
+ import { decodeAxmMeta, decodePurl, parseJsonOptional, readFileOptional } from "./reader-io.js";
18
+ const luarocksType = Schema.decodeUnknownSync(PackageTypeSchema)("luarocks");
19
+ /** Dependencies to skip (Lua runtime itself). */
20
+ const SKIP_DEPS = new Set(["lua"]);
21
+ /**
22
+ * Parse a single dependency string from a rockspec dependencies table.
23
+ * Format: "name [operator version]"
24
+ * Examples: "luasocket >= 3.0", "luafilesystem", "cjson == 1.0.0-1"
25
+ */
26
+ const parseLuaDep = (entry) => {
27
+ const trimmed = entry.trim().replace(/^["']|["']$/g, "");
28
+ if (trimmed === "")
29
+ return undefined;
30
+ const parts = trimmed.split(/\s+/);
31
+ const name = parts[0];
32
+ if (name === undefined || name === "")
33
+ return undefined;
34
+ if (SKIP_DEPS.has(name.toLowerCase()))
35
+ return undefined;
36
+ // Check for exact version: name == version
37
+ if (parts[1] === "==" && parts[2] !== undefined) {
38
+ return { name, version: parts[2] };
39
+ }
40
+ // Any other operator or no version => versionless
41
+ return { name };
42
+ };
43
+ /**
44
+ * Parse a rockspec dependencies table from file content.
45
+ * The dependencies table has the form:
46
+ * dependencies = { "dep1", "dep2 >= 1.0", ... }
47
+ * This is a Lua table literal, so we use regex to extract entries.
48
+ */
49
+ const parseRockspecDeps = (content, source) => {
50
+ const results = [];
51
+ // Find dependencies table - may span multiple lines
52
+ const depsRegex = /dependencies\s*=\s*\{([^}]*)}/s;
53
+ const match = depsRegex.exec(content);
54
+ if (match === null || match[1] === undefined)
55
+ return [];
56
+ // Extract quoted strings from the table
57
+ const stringRegex = /["']([^"']+)["']/g;
58
+ let strMatch;
59
+ while ((strMatch = stringRegex.exec(match[1])) !== null) {
60
+ const entry = strMatch[1];
61
+ if (entry === undefined)
62
+ continue;
63
+ const parsed = parseLuaDep(entry);
64
+ if (parsed === undefined)
65
+ continue;
66
+ const purl = new PackageURL("luarocks", null, parsed.name, parsed.version ?? null, null, null);
67
+ const purlParts = decodePurl(purl.toString());
68
+ results.push({ purl: purlParts, type: luarocksType, source });
69
+ }
70
+ return results;
71
+ };
72
+ /**
73
+ * LuaRocks package detector.
74
+ *
75
+ * Scans `*.rockspec` files in the project directory and extracts
76
+ * dependencies from the `dependencies` table. Skips the `lua` runtime.
77
+ * Multiple rockspec files are processed and results deduplicated.
78
+ *
79
+ * @experimental This API is unstable and may change without notice.
80
+ */
81
+ export const luarocksDetector = {
82
+ type: luarocksType,
83
+ detect: Effect.fn("detect.luarocks")(function* (projectDir) {
84
+ const path = yield* Path.Path;
85
+ const fs = yield* FileSystem.FileSystem;
86
+ const entries = yield* fs.readDirectory(projectDir).pipe(Effect.option);
87
+ if (Option.isNone(entries))
88
+ return [];
89
+ const rockspecFiles = entries.value.filter((e) => e.endsWith(".rockspec"));
90
+ if (rockspecFiles.length === 0)
91
+ return [];
92
+ const allDeps = [];
93
+ const seenNames = new Set();
94
+ for (const rockspecFile of rockspecFiles) {
95
+ const filePath = path.join(projectDir, rockspecFile);
96
+ const content = yield* readFileOptional(filePath);
97
+ if (Option.isNone(content))
98
+ continue;
99
+ const deps = parseRockspecDeps(content.value, filePath);
100
+ if (deps.length === 0 && content.value.trim().length > 0) {
101
+ // Content exists but no deps - check if it looks like a valid rockspec
102
+ if (!content.value.includes("package") && !content.value.includes("rockspec_format")) {
103
+ yield* Effect.logWarning(`Malformed rockspec file: ${rockspecFile}, skipping`);
104
+ }
105
+ }
106
+ for (const dep of deps) {
107
+ if (!seenNames.has(dep.purl.name)) {
108
+ seenNames.add(dep.purl.name);
109
+ allDeps.push(dep);
110
+ }
111
+ }
112
+ }
113
+ return allDeps;
114
+ }, Effect.annotateLogs({ detector: "luarocks" }), Effect.withSpan("detect.luarocks")),
115
+ };
116
+ /**
117
+ * LuaRocks package reader.
118
+ *
119
+ * Reads `axm/axm.json` sidecar from the LuaRocks install tree.
120
+ * Checks system tree (`/usr/local/lib/luarocks/rocks-5.x/`) and
121
+ * user tree (`~/.luarocks/lib/luarocks/rocks-5.x/`).
122
+ *
123
+ * @experimental This API is unstable and may change without notice.
124
+ */
125
+ export const luarocksReader = {
126
+ type: luarocksType,
127
+ read: Effect.fn("read.luarocks")(function* (pkg) {
128
+ const path = yield* Path.Path;
129
+ const pkgName = pkg.purl.name;
130
+ const version = pkg.purl.version ?? "0.0.0-0";
131
+ const home = os.homedir();
132
+ // Lua version variants to check
133
+ const luaVersions = ["5.4", "5.3", "5.2", "5.1"];
134
+ // Candidate base paths
135
+ const basePaths = [
136
+ "/usr/local/lib/luarocks",
137
+ path.join(home, ".luarocks", "lib", "luarocks"),
138
+ ];
139
+ for (const basePath of basePaths) {
140
+ for (const luaVer of luaVersions) {
141
+ const axmJsonPath = path.join(basePath, `rocks-${luaVer}`, pkgName, version, "axm", "axm.json");
142
+ const content = yield* readFileOptional(axmJsonPath);
143
+ if (Option.isNone(content))
144
+ continue;
145
+ const parsed = yield* parseJsonOptional(content.value, `${pkgName}/${version}/axm/axm.json`);
146
+ if (Option.isNone(parsed))
147
+ return Option.none();
148
+ const metaResult = decodeAxmMeta(parsed.value);
149
+ if (Result.isFailure(metaResult)) {
150
+ yield* Effect.logWarning(`Invalid axm metadata in ${pkgName}: schema validation failed`);
151
+ return Option.none();
152
+ }
153
+ return Option.some(metaResult.success.extensions);
154
+ }
155
+ }
156
+ return Option.none();
157
+ }, Effect.annotateLogs({ reader: "luarocks" }), Effect.withSpan("read.luarocks")),
158
+ };
159
+ //# sourceMappingURL=luarocks.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Maven/Gradle package 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
+ * Maven package detector.
10
+ *
11
+ * Scans `pom.xml`, `build.gradle`, `build.gradle.kts`, and
12
+ * `gradle/libs.versions.toml` in the project directory. Also detects Clojure
13
+ * `deps.edn` Maven coordinates declared with `:mvn/version`.
14
+ *
15
+ * @experimental This API is unstable and may change without notice.
16
+ */
17
+ export declare const mavenDetector: PackageDetector;
18
+ /**
19
+ * Maven package reader.
20
+ *
21
+ * Reads `META-INF/axm.json` from local JAR files in `~/.m2/repository/`
22
+ * or Gradle cache `~/.gradle/caches/modules-2/files-2.1/`.
23
+ *
24
+ * @experimental This API is unstable and may change without notice.
25
+ */
26
+ export declare const mavenReader: PackageReader;
27
+ //# sourceMappingURL=maven.d.ts.map