@agentxm/extension-sources 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 (101) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +9 -0
  3. package/dist/src/axm-skill-gate.d.ts +64 -0
  4. package/dist/src/axm-skill-gate.js +25 -0
  5. package/dist/src/errors.d.ts +116 -0
  6. package/dist/src/errors.js +98 -0
  7. package/dist/src/failure-category.d.ts +10 -0
  8. package/dist/src/failure-category.js +2 -0
  9. package/dist/src/file-url.d.ts +9 -0
  10. package/dist/src/file-url.js +12 -0
  11. package/dist/src/git/detect.d.ts +7 -0
  12. package/dist/src/git/detect.js +23 -0
  13. package/dist/src/git/operations.d.ts +37 -0
  14. package/dist/src/git/operations.js +101 -0
  15. package/dist/src/glob.d.ts +39 -0
  16. package/dist/src/glob.js +79 -0
  17. package/dist/src/hook-package-discovery.d.ts +19 -0
  18. package/dist/src/hook-package-discovery.js +14 -0
  19. package/dist/src/index.d.ts +30 -0
  20. package/dist/src/index.js +35 -0
  21. package/dist/src/integrity.d.ts +13 -0
  22. package/dist/src/integrity.js +17 -0
  23. package/dist/src/live.d.ts +29 -0
  24. package/dist/src/live.js +131 -0
  25. package/dist/src/manifest-package-discovery.d.ts +28 -0
  26. package/dist/src/manifest-package-discovery.js +96 -0
  27. package/dist/src/package-discovery.d.ts +19 -0
  28. package/dist/src/package-discovery.js +137 -0
  29. package/dist/src/package-sources.d.ts +25 -0
  30. package/dist/src/package-sources.js +102 -0
  31. package/dist/src/providers/azurerepos/index.d.ts +11 -0
  32. package/dist/src/providers/azurerepos/index.js +11 -0
  33. package/dist/src/providers/azurerepos/repo-exists.d.ts +5 -0
  34. package/dist/src/providers/azurerepos/repo-exists.js +21 -0
  35. package/dist/src/providers/azurerepos/scp.d.ts +12 -0
  36. package/dist/src/providers/azurerepos/scp.js +29 -0
  37. package/dist/src/providers/azurerepos/shorthand.d.ts +12 -0
  38. package/dist/src/providers/azurerepos/shorthand.js +45 -0
  39. package/dist/src/providers/azurerepos/url.d.ts +14 -0
  40. package/dist/src/providers/azurerepos/url.js +38 -0
  41. package/dist/src/providers/bitbucket/index.d.ts +11 -0
  42. package/dist/src/providers/bitbucket/index.js +11 -0
  43. package/dist/src/providers/bitbucket/resolve-repo.d.ts +11 -0
  44. package/dist/src/providers/bitbucket/resolve-repo.js +33 -0
  45. package/dist/src/providers/bitbucket/scp.d.ts +11 -0
  46. package/dist/src/providers/bitbucket/scp.js +28 -0
  47. package/dist/src/providers/bitbucket/shorthand.d.ts +10 -0
  48. package/dist/src/providers/bitbucket/shorthand.js +11 -0
  49. package/dist/src/providers/bitbucket/url.d.ts +13 -0
  50. package/dist/src/providers/bitbucket/url.js +42 -0
  51. package/dist/src/providers/convention-discovery.d.ts +11 -0
  52. package/dist/src/providers/convention-discovery.js +473 -0
  53. package/dist/src/providers/git-hosting.d.ts +31 -0
  54. package/dist/src/providers/git-hosting.js +73 -0
  55. package/dist/src/providers/git.d.ts +22 -0
  56. package/dist/src/providers/git.js +46 -0
  57. package/dist/src/providers/github/index.d.ts +11 -0
  58. package/dist/src/providers/github/index.js +11 -0
  59. package/dist/src/providers/github/resolve-repo.d.ts +11 -0
  60. package/dist/src/providers/github/resolve-repo.js +34 -0
  61. package/dist/src/providers/github/scp.d.ts +11 -0
  62. package/dist/src/providers/github/scp.js +28 -0
  63. package/dist/src/providers/github/shorthand.d.ts +10 -0
  64. package/dist/src/providers/github/shorthand.js +11 -0
  65. package/dist/src/providers/github/url.d.ts +13 -0
  66. package/dist/src/providers/github/url.js +42 -0
  67. package/dist/src/providers/gitlab/index.d.ts +11 -0
  68. package/dist/src/providers/gitlab/index.js +11 -0
  69. package/dist/src/providers/gitlab/resolve-repo.d.ts +11 -0
  70. package/dist/src/providers/gitlab/resolve-repo.js +33 -0
  71. package/dist/src/providers/gitlab/scp.d.ts +11 -0
  72. package/dist/src/providers/gitlab/scp.js +28 -0
  73. package/dist/src/providers/gitlab/shorthand.d.ts +10 -0
  74. package/dist/src/providers/gitlab/shorthand.js +11 -0
  75. package/dist/src/providers/gitlab/url.d.ts +13 -0
  76. package/dist/src/providers/gitlab/url.js +42 -0
  77. package/dist/src/providers/local-parser/index.d.ts +8 -0
  78. package/dist/src/providers/local-parser/index.js +8 -0
  79. package/dist/src/providers/local-parser/parser.d.ts +13 -0
  80. package/dist/src/providers/local-parser/parser.js +14 -0
  81. package/dist/src/providers/local.d.ts +23 -0
  82. package/dist/src/providers/local.js +39 -0
  83. package/dist/src/providers/parse-provider-shorthand.d.ts +18 -0
  84. package/dist/src/providers/parse-provider-shorthand.js +74 -0
  85. package/dist/src/providers/registry/host-provider.d.ts +47 -0
  86. package/dist/src/providers/registry/host-provider.js +584 -0
  87. package/dist/src/resolve-identifier.d.ts +73 -0
  88. package/dist/src/resolve-identifier.js +273 -0
  89. package/dist/src/resolve-source-pattern.d.ts +29 -0
  90. package/dist/src/resolve-source-pattern.js +77 -0
  91. package/dist/src/resolve-source.d.ts +79 -0
  92. package/dist/src/resolve-source.js +503 -0
  93. package/dist/src/rule-package-discovery.d.ts +19 -0
  94. package/dist/src/rule-package-discovery.js +14 -0
  95. package/dist/src/service.d.ts +72 -0
  96. package/dist/src/service.js +109 -0
  97. package/dist/src/url-fragment.d.ts +5 -0
  98. package/dist/src/url-fragment.js +19 -0
  99. package/dist/src/workspace-catalog.d.ts +79 -0
  100. package/dist/src/workspace-catalog.js +26 -0
  101. package/package.json +57 -0
@@ -0,0 +1,73 @@
1
+ import * as Effect from "effect/Effect";
2
+ import type * as FileSystem from "effect/FileSystem";
3
+ import type * as HttpClient from "effect/unstable/http/HttpClient";
4
+ import * as Option from "effect/Option";
5
+ import type * as Path from "effect/Path";
6
+ import { SourceNotResolvable, type SourceResolutionFailure } from "./errors.js";
7
+ import { type CatalogExtensionType } from "@agentxm/extension-model/unstable/extension-types/schema";
8
+ import { type ExtensionName, type Handle } from "@agentxm/extension-model/unstable/extensions";
9
+ import { WorkspaceCatalog } from "./workspace-catalog.js";
10
+ /**
11
+ * Every non-pack extension type an installed identifier can name. Packs are
12
+ * excluded because they are containers: a pack has no per-type lock map of its
13
+ * own to resolve a bare name against.
14
+ */
15
+ export type IdentifierResourceType = CatalogExtensionType;
16
+ export type IdentifierResolutionScope = "installed" | "registry" | "both";
17
+ export interface ResolvedIdentifier {
18
+ readonly input: string;
19
+ readonly owner: Option.Option<Handle>;
20
+ readonly type: IdentifierResourceType;
21
+ readonly name: ExtensionName;
22
+ readonly fqn: string;
23
+ readonly installedName: Option.Option<string>;
24
+ readonly registryLocation: Option.Option<URL>;
25
+ readonly registrySourceName: Option.Option<string>;
26
+ readonly source: "installed" | "registry" | "passthrough";
27
+ }
28
+ export interface ResolveIdentifierArgs {
29
+ readonly input: string;
30
+ readonly resourceType: IdentifierResourceType;
31
+ readonly scope: IdentifierResolutionScope;
32
+ readonly registrySourceName: string;
33
+ }
34
+ export declare const resolveIdentifier: (args: ResolveIdentifierArgs) => Effect.Effect<{
35
+ input: string;
36
+ owner: Option.Option<string & import("effect/Brand").Brand<"Handle">>;
37
+ type: "skill" | "mcp-server" | "subagent" | "rule" | "hook" | "knowledge";
38
+ name: string & import("effect/Brand").Brand<"ExtensionName">;
39
+ fqn: string;
40
+ installedName: Option.Option<string>;
41
+ registryLocation: Option.Option<URL>;
42
+ registrySourceName: Option.Option<string>;
43
+ source: "registry" | "installed";
44
+ } | {
45
+ input: string;
46
+ owner: Option.Option<string & import("effect/Brand").Brand<"Handle">>;
47
+ type: "skill" | "mcp-server" | "subagent" | "rule" | "hook" | "knowledge";
48
+ name: string & import("effect/Brand").Brand<"ExtensionName">;
49
+ fqn: string;
50
+ installedName: Option.Option<string & import("effect/Brand").Brand<"ExtensionName">>;
51
+ registryLocation: Option.Option<URL>;
52
+ registrySourceName: Option.Option<string>;
53
+ source: "passthrough";
54
+ }, SourceResolutionFailure, FileSystem.FileSystem | Path.Path | WorkspaceCatalog | HttpClient.HttpClient>;
55
+ export declare const resolveInstalledIdentifier: (args: {
56
+ readonly input: string;
57
+ readonly resourceType: IdentifierResourceType;
58
+ }) => Effect.Effect<{
59
+ input: string;
60
+ owner: Option.Option<string & import("effect/Brand").Brand<"Handle">>;
61
+ type: "skill" | "mcp-server" | "subagent" | "rule" | "hook" | "knowledge";
62
+ name: string & import("effect/Brand").Brand<"ExtensionName">;
63
+ fqn: string;
64
+ installedName: Option.Option<string>;
65
+ registryLocation: Option.Option<URL>;
66
+ registrySourceName: Option.Option<string>;
67
+ source: "registry" | "installed";
68
+ }, SourceResolutionFailure, WorkspaceCatalog>;
69
+ export declare const resolveInstalledIdentifierNameOrInput: (args: {
70
+ readonly input: string;
71
+ readonly resourceType: IdentifierResourceType;
72
+ }) => Effect.Effect<string, import("./axm-skill-gate.ts").AxmSkillGateUnavailable | import("./workspace-catalog.js").WorkspaceCatalogUnavailable | import("./errors.js").SourceSyntaxInvalid | import("./errors.js").SourceHostNotConfigured | SourceNotResolvable | import("./errors.js").SourceNetworkFailure | import("./errors.js").GitOperationFailed | import("@agentxm/registry-client").RegistryProblem | import("@agentxm/registry-client").RegistryRequestFailed | import("@agentxm/registry-client").RegistryOperationFailed, WorkspaceCatalog>;
73
+ //# sourceMappingURL=resolve-identifier.d.ts.map
@@ -0,0 +1,273 @@
1
+ import * as Array from "effect/Array";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Option from "effect/Option";
4
+ import * as Result from "effect/Result";
5
+ import { SourceNotResolvable, sourceResolutionFailureCategory, } from "./errors.js";
6
+ import { isCatalogExtensionType, } from "@agentxm/extension-model/unstable/extension-types/schema";
7
+ import { decodeExtensionNameSync, extensionTypePluralSentenceLabels, formatFqn, parseExtensionFqnParts, parseSourceQualifiedRegistrySourcePatternParts, toExtensionTypePlural, } from "@agentxm/extension-model/unstable/extensions";
8
+ import { createRegistryClient } from "@agentxm/registry-client";
9
+ import { WorkspaceCatalog } from "./workspace-catalog.js";
10
+ const isIdentifierResourceType = (type) => isCatalogExtensionType(type);
11
+ const decodeName = (input) => Effect.try({
12
+ try: () => decodeExtensionNameSync(input),
13
+ catch: () => new SourceNotResolvable({
14
+ category: "not_found",
15
+ detail: `No ${input} identifier could be resolved`,
16
+ suggestions: [
17
+ {
18
+ description: "Use a valid bare name, or use a fully-qualified name like @owner/skills/name.",
19
+ },
20
+ ],
21
+ }),
22
+ });
23
+ const makeCandidate = (parts, installedName, source) => ({
24
+ owner: Option.some(parts.owner),
25
+ type: parts.type,
26
+ name: parts.name,
27
+ fqn: formatFqn(parts),
28
+ installedName,
29
+ registryLocation: Option.none(),
30
+ registrySourceName: Option.none(),
31
+ source,
32
+ });
33
+ const configuredSourceParts = (resourceType, source) => {
34
+ const parsed = parseSourceQualifiedRegistrySourcePatternParts(source);
35
+ if (parsed === undefined || parsed.name === undefined)
36
+ return Option.none();
37
+ if (parsed.type !== undefined && parsed.type !== toExtensionTypePlural(resourceType)) {
38
+ return Option.none();
39
+ }
40
+ return Option.some({
41
+ owner: parsed.owner,
42
+ type: resourceType,
43
+ name: parsed.name,
44
+ });
45
+ };
46
+ const matchesInput = (input, candidate) => candidate.fqn === input ||
47
+ candidate.name === input ||
48
+ (Option.isSome(candidate.installedName) && candidate.installedName.value === input);
49
+ const dedupeCandidates = (candidates) => {
50
+ const deduped = [];
51
+ const chooseCandidate = (existing, next) => {
52
+ if (Option.isNone(existing.owner) && Option.isSome(next.owner))
53
+ return next;
54
+ return existing;
55
+ };
56
+ for (const candidate of candidates) {
57
+ if (Option.isSome(candidate.installedName)) {
58
+ const candidateInstalledName = candidate.installedName.value;
59
+ const existingIndex = deduped.findIndex((entry) => Option.isSome(entry.installedName) &&
60
+ entry.installedName.value === candidateInstalledName);
61
+ const existing = deduped[existingIndex];
62
+ if (existing !== undefined) {
63
+ deduped[existingIndex] = chooseCandidate(existing, candidate);
64
+ continue;
65
+ }
66
+ }
67
+ const existingFqnIndex = deduped.findIndex((entry) => entry.fqn === candidate.fqn);
68
+ const existingFqn = deduped[existingFqnIndex];
69
+ if (existingFqn !== undefined) {
70
+ deduped[existingFqnIndex] = chooseCandidate(existingFqn, candidate);
71
+ continue;
72
+ }
73
+ deduped.push(candidate);
74
+ }
75
+ return deduped;
76
+ };
77
+ const installedCandidates = (input, resourceType) => Effect.gen(function* () {
78
+ const catalog = yield* WorkspaceCatalog;
79
+ const candidates = [];
80
+ const graph = yield* catalog.desiredExtensionGraph;
81
+ if (!graph.complete) {
82
+ return yield* new SourceNotResolvable({
83
+ category: "conflict",
84
+ detail: "The desired extension graph is incomplete, so installed identifiers cannot be resolved safely.",
85
+ suggestions: [
86
+ {
87
+ description: "Repair or reinstall the configured packs, then retry.",
88
+ cmd: "axm sync",
89
+ },
90
+ ],
91
+ });
92
+ }
93
+ for (const node of graph.nodes) {
94
+ if (node.type !== resourceType)
95
+ continue;
96
+ if (node.source === undefined)
97
+ continue;
98
+ const graphIdentity = node.identity.startsWith("workspace:")
99
+ ? node.identity.slice("workspace:".length)
100
+ : node.identity;
101
+ const parsedIdentity = parseExtensionFqnParts(graphIdentity);
102
+ const parts = parsedIdentity !== undefined && parsedIdentity.type === resourceType
103
+ ? Option.some({
104
+ owner: parsedIdentity.owner,
105
+ type: resourceType,
106
+ name: parsedIdentity.name,
107
+ })
108
+ : configuredSourceParts(resourceType, node.source);
109
+ if (Option.isSome(parts)) {
110
+ candidates.push(makeCandidate(parts.value, Option.some(node.name), "installed"));
111
+ }
112
+ else if (node.name === input) {
113
+ const decodedName = yield* decodeName(node.name);
114
+ candidates.push({
115
+ owner: Option.none(),
116
+ type: resourceType,
117
+ name: decodedName,
118
+ fqn: node.name,
119
+ installedName: Option.some(node.name),
120
+ registryLocation: Option.none(),
121
+ registrySourceName: Option.none(),
122
+ source: "installed",
123
+ });
124
+ }
125
+ }
126
+ return dedupeCandidates(candidates).filter((candidate) => matchesInput(input, candidate));
127
+ });
128
+ const registryCandidates = (input, resourceType, registrySourceName) => Effect.gen(function* () {
129
+ const name = yield* decodeName(input);
130
+ const catalog = yield* WorkspaceCatalog;
131
+ const registrySources = (yield* catalog.registrySourceHosts).filter((source) => source.name === registrySourceName);
132
+ const results = yield* Effect.forEach(registrySources, (sourceConfig) => Effect.gen(function* () {
133
+ const location = sourceConfig.location.protocol === "file:"
134
+ ? sourceConfig.location.pathname
135
+ : sourceConfig.location.href;
136
+ const client = yield* createRegistryClient(location);
137
+ const result = yield* client.getExtensionsByScope({
138
+ owner: "*",
139
+ names: [name],
140
+ types: [resourceType],
141
+ limit: Option.none(),
142
+ offset: 0,
143
+ });
144
+ return result.extensions.map((entry) => ({
145
+ ...makeCandidate({
146
+ owner: entry.owner,
147
+ type: resourceType,
148
+ name: entry.name,
149
+ }, Option.none(), "registry"),
150
+ registryLocation: Option.some(sourceConfig.location),
151
+ registrySourceName: Option.some(sourceConfig.name),
152
+ }));
153
+ }).pipe(Effect.result), { concurrency: "unbounded" });
154
+ return dedupeCandidates(Array.flatten(Array.getSuccesses(results).map((result) => result.filter((candidate) => candidate.name === name))));
155
+ });
156
+ const notFound = (input, resourceType, scope) => new SourceNotResolvable({
157
+ category: "not_found",
158
+ detail: `"${input}" did not match any ${extensionTypePluralSentenceLabels[toExtensionTypePlural(resourceType)]} in ${scope} scope`,
159
+ suggestions: [{ description: "Check the name, or re-run with a fully-qualified name." }],
160
+ });
161
+ const ambiguous = (input, resourceType, scope, candidates) => new SourceNotResolvable({
162
+ category: "internal",
163
+ detail: `"${input}" matches more than one ${scope} ${extensionTypePluralSentenceLabels[toExtensionTypePlural(resourceType)]}: ${candidates.map((candidate) => candidate.fqn).join(", ")}`,
164
+ suggestions: [{ description: "Re-run with the fully-qualified name." }],
165
+ });
166
+ const resolveFromCandidates = (input, resourceType, scope, candidates) => Effect.gen(function* () {
167
+ if (candidates.length === 0) {
168
+ return yield* notFound(input, resourceType, scope);
169
+ }
170
+ if (candidates.length > 1) {
171
+ return yield* ambiguous(input, resourceType, scope, candidates);
172
+ }
173
+ const [candidate] = candidates;
174
+ if (candidate === undefined) {
175
+ return yield* notFound(input, resourceType, scope);
176
+ }
177
+ return {
178
+ input,
179
+ owner: candidate.owner,
180
+ type: candidate.type,
181
+ name: candidate.name,
182
+ fqn: candidate.fqn,
183
+ installedName: candidate.installedName,
184
+ registryLocation: candidate.registryLocation,
185
+ registrySourceName: candidate.registrySourceName,
186
+ source: candidate.source,
187
+ };
188
+ });
189
+ export const resolveIdentifier = (args) => Effect.gen(function* () {
190
+ const trimmed = args.input.trim();
191
+ const parsed = parseExtensionFqnParts(trimmed);
192
+ if (parsed !== undefined) {
193
+ if (!isIdentifierResourceType(parsed.type) || parsed.type !== args.resourceType) {
194
+ return yield* new SourceNotResolvable({
195
+ category: "not_found",
196
+ detail: `"${trimmed}" is not a ${args.resourceType} identifier`,
197
+ suggestions: [
198
+ {
199
+ description: `Use a ${args.resourceType} identifier like @owner/${toExtensionTypePlural(args.resourceType)}/name.`,
200
+ },
201
+ ],
202
+ });
203
+ }
204
+ if (args.scope === "installed" || args.scope === "both") {
205
+ const installed = yield* installedCandidates(trimmed, args.resourceType);
206
+ if (installed.length > 0) {
207
+ return yield* resolveFromCandidates(trimmed, args.resourceType, "installed", installed);
208
+ }
209
+ if (args.scope === "installed") {
210
+ return yield* notFound(trimmed, args.resourceType, args.scope);
211
+ }
212
+ }
213
+ return {
214
+ input: trimmed,
215
+ owner: Option.some(parsed.owner),
216
+ type: args.resourceType,
217
+ name: parsed.name,
218
+ fqn: formatFqn(parsed),
219
+ installedName: Option.some(parsed.name),
220
+ registryLocation: Option.none(),
221
+ registrySourceName: Option.some(args.registrySourceName),
222
+ source: "passthrough",
223
+ };
224
+ }
225
+ switch (args.scope) {
226
+ case "installed": {
227
+ const candidates = yield* installedCandidates(trimmed, args.resourceType);
228
+ return yield* resolveFromCandidates(trimmed, args.resourceType, args.scope, candidates);
229
+ }
230
+ case "registry": {
231
+ const candidates = yield* registryCandidates(trimmed, args.resourceType, args.registrySourceName);
232
+ return yield* resolveFromCandidates(trimmed, args.resourceType, args.scope, candidates);
233
+ }
234
+ case "both": {
235
+ const installed = yield* installedCandidates(trimmed, args.resourceType);
236
+ if (installed.length > 0) {
237
+ return yield* resolveFromCandidates(trimmed, args.resourceType, "installed", installed);
238
+ }
239
+ const registry = yield* registryCandidates(trimmed, args.resourceType, args.registrySourceName);
240
+ return yield* resolveFromCandidates(trimmed, args.resourceType, "registry", registry);
241
+ }
242
+ }
243
+ });
244
+ export const resolveInstalledIdentifier = (args) => Effect.gen(function* () {
245
+ const trimmed = args.input.trim();
246
+ const parsed = parseExtensionFqnParts(trimmed);
247
+ if (parsed !== undefined) {
248
+ if (!isIdentifierResourceType(parsed.type) || parsed.type !== args.resourceType) {
249
+ return yield* new SourceNotResolvable({
250
+ category: "not_found",
251
+ detail: `"${trimmed}" is not a ${args.resourceType} identifier`,
252
+ suggestions: [
253
+ {
254
+ description: `Use a ${args.resourceType} identifier like @owner/${toExtensionTypePlural(args.resourceType)}/name.`,
255
+ },
256
+ ],
257
+ });
258
+ }
259
+ }
260
+ const candidates = yield* installedCandidates(trimmed, args.resourceType);
261
+ return yield* resolveFromCandidates(trimmed, args.resourceType, "installed", candidates);
262
+ });
263
+ export const resolveInstalledIdentifierNameOrInput = (args) => Effect.gen(function* () {
264
+ const trimmed = args.input.trim();
265
+ const result = yield* Effect.result(resolveInstalledIdentifier(args));
266
+ if (Result.isFailure(result)) {
267
+ if (sourceResolutionFailureCategory(result.failure) === "not_found")
268
+ return trimmed;
269
+ return yield* result.failure;
270
+ }
271
+ return Option.getOrElse(result.success.installedName, () => result.success.name);
272
+ });
273
+ //# sourceMappingURL=resolve-identifier.js.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Multi-source pattern resolution: handles both single sources and glob patterns.
3
+ *
4
+ * Wraps `resolveSource` for single inputs and expands globs against all known
5
+ * skills (locked, configured, and on-disk) to resolve multiple sources.
6
+ *
7
+ * @experimental This API is unstable and may change without notice.
8
+ * @packageDocumentation
9
+ */
10
+ import type * as FileSystem from "effect/FileSystem";
11
+ import type * as HttpClient from "effect/unstable/http/HttpClient";
12
+ import type * as Path from "effect/Path";
13
+ import * as Effect from "effect/Effect";
14
+ import { type SourceResolutionFailure } from "./errors.js";
15
+ import { WorkspaceCatalog } from "./workspace-catalog.js";
16
+ import type { Source } from "@agentxm/extension-model/unstable/sources/types";
17
+ /**
18
+ * Resolve a source pattern into one or more `Source` values.
19
+ *
20
+ * - Single input (name, path, URL, etc.) → delegates to `resolveSource`, returns single-element array
21
+ * - Glob pattern (e.g. `effect-*`) → expands against locked, configured, and on-disk skills
22
+ *
23
+ * For single name inputs, includes fallbacks to configured skills and on-disk discovery
24
+ * when the skill is not in the lockfile.
25
+ *
26
+ * @experimental This API is unstable and may change without notice.
27
+ */
28
+ export declare const resolveSourcePattern: (input: string) => Effect.Effect<ReadonlyArray<Source>, SourceResolutionFailure, WorkspaceCatalog | FileSystem.FileSystem | HttpClient.HttpClient | Path.Path>;
29
+ //# sourceMappingURL=resolve-source-pattern.d.ts.map
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Multi-source pattern resolution: handles both single sources and glob patterns.
3
+ *
4
+ * Wraps `resolveSource` for single inputs and expands globs against all known
5
+ * skills (locked, configured, and on-disk) to resolve multiple sources.
6
+ *
7
+ * @experimental This API is unstable and may change without notice.
8
+ * @packageDocumentation
9
+ */
10
+ import * as Effect from "effect/Effect";
11
+ import { SourceNotResolvable, sourceResolutionFailureCategory, } from "./errors.js";
12
+ import { expandGlobs, isGlobPattern } from "./glob.js";
13
+ import { resolveSource } from "./resolve-source.js";
14
+ import { WorkspaceCatalog } from "./workspace-catalog.js";
15
+ // -----------------------------------------------------------------------------
16
+ // Helpers
17
+ // -----------------------------------------------------------------------------
18
+ const sortNames = (names) => [...names].sort((a, b) => a.localeCompare(b));
19
+ /** Resolve a single skill name with fallbacks: resolveSource → configured source → on-disk path. */
20
+ const resolveNameWithFallback = (name, configuredSkills, onDiskByName) => resolveSource(name).pipe(Effect.catch((error) => {
21
+ if (sourceResolutionFailureCategory(error) !== "validation") {
22
+ return Effect.fail(error);
23
+ }
24
+ const configuredEntry = configuredSkills[name];
25
+ if (configuredEntry?.source !== undefined) {
26
+ return resolveSource(configuredEntry.source);
27
+ }
28
+ const diskPath = onDiskByName.get(name);
29
+ if (diskPath !== undefined) {
30
+ return Effect.succeed({ type: "local", path: diskPath });
31
+ }
32
+ return Effect.fail(error);
33
+ }));
34
+ // -----------------------------------------------------------------------------
35
+ // Main
36
+ // -----------------------------------------------------------------------------
37
+ /**
38
+ * Resolve a source pattern into one or more `Source` values.
39
+ *
40
+ * - Single input (name, path, URL, etc.) → delegates to `resolveSource`, returns single-element array
41
+ * - Glob pattern (e.g. `effect-*`) → expands against locked, configured, and on-disk skills
42
+ *
43
+ * For single name inputs, includes fallbacks to configured skills and on-disk discovery
44
+ * when the skill is not in the lockfile.
45
+ *
46
+ * @experimental This API is unstable and may change without notice.
47
+ */
48
+ export const resolveSourcePattern = (input) => isGlobPattern(input)
49
+ ? Effect.gen(function* () {
50
+ const catalog = yield* WorkspaceCatalog;
51
+ const candidates = yield* catalog.skillCandidates;
52
+ const matchedNames = expandGlobs([input], candidates.names);
53
+ if (matchedNames.length === 0) {
54
+ return yield* new SourceNotResolvable({
55
+ category: "not_found",
56
+ detail: "No skills matched the given pattern",
57
+ suggestions: [
58
+ {
59
+ description: "Inspect installed skills.",
60
+ cmd: "axm skills list",
61
+ },
62
+ ],
63
+ });
64
+ }
65
+ return yield* Effect.forEach(sortNames(matchedNames), (name) => resolveNameWithFallback(name, candidates.configuredSkills, candidates.onDiskByName), { concurrency: "unbounded" });
66
+ })
67
+ : resolveSource(input).pipe(Effect.catch((error) => {
68
+ if (sourceResolutionFailureCategory(error) !== "validation") {
69
+ return Effect.fail(error);
70
+ }
71
+ return Effect.gen(function* () {
72
+ const catalog = yield* WorkspaceCatalog;
73
+ const candidates = yield* catalog.skillCandidates;
74
+ return yield* resolveNameWithFallback(input, candidates.configuredSkills, candidates.onDiskByName);
75
+ });
76
+ }), Effect.map((source) => [source]));
77
+ //# sourceMappingURL=resolve-source-pattern.js.map
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Source resolution: classifies input via parseInputPattern, then routes
3
+ * each pattern type to the appropriate resolution logic.
4
+ *
5
+ * For URL and SCP patterns, resolution iterates configured sources and
6
+ * matches by hostname + provider parse. For other patterns, resolution
7
+ * handles them directly.
8
+ *
9
+ * @experimental This API is unstable and may change without notice.
10
+ * @packageDocumentation
11
+ */
12
+ import type * as FileSystem from "effect/FileSystem";
13
+ import type * as HttpClient from "effect/unstable/http/HttpClient";
14
+ import type * as Path from "effect/Path";
15
+ import * as Effect from "effect/Effect";
16
+ import * as Option from "effect/Option";
17
+ import type { InputParseResult, ShorthandInput } from "@agentxm/extension-model/unstable/sources/parser";
18
+ import type { Source } from "@agentxm/extension-model/unstable/sources/types";
19
+ import { type Handle } from "@agentxm/extension-model/unstable/extensions/handle";
20
+ import type { ExtensionName, ExtensionType, ExtensionTypePlural } from "@agentxm/extension-model/unstable/extensions";
21
+ import { SourceHostNotConfigured, SourceNotResolvable, SourceSyntaxInvalid, type SourceResolutionFailure } from "./errors.js";
22
+ import { WorkspaceCatalog } from "./workspace-catalog.js";
23
+ /**
24
+ * Route a URL input by iterating configured sources and matching by
25
+ * hostname + provider parse. First successful match wins.
26
+ */
27
+ export declare const routeUrlInput: (url: URL, input: string) => Effect.Effect<Source, SourceSyntaxInvalid | SourceHostNotConfigured | SourceNotResolvable, WorkspaceCatalog>;
28
+ /**
29
+ * Route an SCP address by iterating configured sources and matching by
30
+ * hostname + provider parse. First successful match wins.
31
+ */
32
+ export declare const routeScpInput: (scp: {
33
+ readonly user: string;
34
+ readonly host: string;
35
+ readonly path: string;
36
+ }, input: string) => Effect.Effect<Source, SourceHostNotConfigured | SourceNotResolvable, WorkspaceCatalog>;
37
+ /**
38
+ * Route shorthand input (github:owner/repo, ghe:owner/repo, etc.).
39
+ *
40
+ * Known source-type prefixes dispatch directly to the provider's shorthand
41
+ * parser. Config-name prefixes look up the config and parse using its source
42
+ * type's shorthand parser.
43
+ */
44
+ export declare const resolveShorthandInputSource: (parseResult: InputParseResult<ShorthandInput>) => Effect.Effect<Source, SourceSyntaxInvalid | SourceHostNotConfigured | SourceNotResolvable, WorkspaceCatalog>;
45
+ /** Route NameInput through the complete desired extension graph. */
46
+ export declare const routeNameInput: (name: string, _input: string, expectedType?: ExtensionType) => Effect.Effect<Source, SourceResolutionFailure, FileSystem.FileSystem | HttpClient.HttpClient | Path.Path | WorkspaceCatalog>;
47
+ /** Route RegistryPatternInput: find matching registry config and intersect with params. */
48
+ export declare const routeRegistryInput: (pattern: {
49
+ readonly sourceName: string;
50
+ readonly type: Option.Option<ExtensionTypePlural>;
51
+ readonly owner: Handle;
52
+ readonly name: Option.Option<ExtensionName>;
53
+ }, _input: string) => Effect.Effect<{
54
+ type: "registry";
55
+ name: string;
56
+ location: URL;
57
+ owner: Option.Option<string & import("effect/Brand").Brand<"Handle">>;
58
+ }, SourceHostNotConfigured | SourceNotResolvable, WorkspaceCatalog>;
59
+ export declare const resolveSlashInputSource: (pattern: {
60
+ readonly first: string;
61
+ readonly second: string;
62
+ readonly third: Option.Option<string>;
63
+ }, input: string) => Effect.Effect<Source, SourceSyntaxInvalid | SourceHostNotConfigured | SourceNotResolvable, FileSystem.FileSystem | Path.Path | WorkspaceCatalog | HttpClient.HttpClient>;
64
+ /**
65
+ * Resolve a source string into a fully resolved `Source`.
66
+ *
67
+ * Classifies the input via `parseInputPattern`, then routes each pattern
68
+ * type to the appropriate resolution logic. For URL and SCP patterns,
69
+ * resolution iterates configured sources and matches by hostname + provider
70
+ * parse. For other patterns, resolution handles them directly.
71
+ *
72
+ * @experimental This API is unstable and may change without notice.
73
+ * @param input - The source string to resolve
74
+ * @returns Effect containing a resolved `Source` or a typed resolution failure
75
+ */
76
+ export declare const resolveSource: (input: string, options?: {
77
+ readonly expectedType?: ExtensionType;
78
+ }) => Effect.Effect<Source, SourceResolutionFailure, FileSystem.FileSystem | HttpClient.HttpClient | Path.Path | WorkspaceCatalog>;
79
+ //# sourceMappingURL=resolve-source.d.ts.map