@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,137 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as FileSystem from "effect/FileSystem";
3
+ import * as Option from "effect/Option";
4
+ import * as Path from "effect/Path";
5
+ import * as Schema from "effect/Schema";
6
+ import { SourceNotResolvable } from "./errors.js";
7
+ import { DISCOVERY_MAX_DEPTH, DISCOVERY_SKIPPED_DIRECTORIES, } from "@agentxm/extension-model/unstable/discovery-walk";
8
+ import { ManifestIdentitySchema, manifestFilenameForType, manifestSchemaForType, validateManifestHasNoAgentsField, } from "@agentxm/registry-protocol/unstable/publish/manifest-policy";
9
+ const typeForManifestFilename = (fileName) => {
10
+ switch (fileName) {
11
+ case "skill.json":
12
+ return "skill";
13
+ case "mcp.json":
14
+ return "mcp-server";
15
+ case "subagent.json":
16
+ return "subagent";
17
+ case "rule.json":
18
+ return "rule";
19
+ case "hook.json":
20
+ return "hook";
21
+ case "knowledge.json":
22
+ return "knowledge";
23
+ case "pack.json":
24
+ return "pack";
25
+ default:
26
+ return undefined;
27
+ }
28
+ };
29
+ const matchesFilter = (identity, filter) => (filter.type === "*" || filter.type === identity.type) &&
30
+ (filter.names.length === 0 || filter.names.includes(identity.name)) &&
31
+ (Option.isNone(filter.owner) || filter.owner.value === identity.owner);
32
+ export const inspectExtensionPackage = (directory) => Effect.gen(function* () {
33
+ const fs = yield* FileSystem.FileSystem;
34
+ const path = yield* Path.Path;
35
+ const entries = yield* fs.readDirectory(directory).pipe(Effect.mapError((cause) => new SourceNotResolvable({
36
+ category: "validation",
37
+ detail: `AXM package directory could not be read: ${directory}`,
38
+ cause,
39
+ })));
40
+ const manifestEntries = entries
41
+ .filter((entry) => typeForManifestFilename(entry) !== undefined)
42
+ .sort();
43
+ const manifestFile = manifestEntries[0];
44
+ if (manifestFile === undefined) {
45
+ return yield* new SourceNotResolvable({
46
+ category: "validation",
47
+ detail: `No AXM extension manifest was found at ${directory}; use skills import or subagents import for supported unmanaged/native content`,
48
+ });
49
+ }
50
+ if (manifestEntries.length > 1) {
51
+ return yield* new SourceNotResolvable({
52
+ category: "validation",
53
+ detail: `Multiple AXM extension manifests were found at ${directory}: ${manifestEntries.join(", ")}`,
54
+ });
55
+ }
56
+ const type = typeForManifestFilename(manifestFile);
57
+ if (type === undefined) {
58
+ return yield* new SourceNotResolvable({
59
+ category: "internal",
60
+ detail: `Manifest type could not be determined for ${manifestFile}`,
61
+ });
62
+ }
63
+ const manifestPath = path.join(directory, manifestFile);
64
+ const text = yield* fs.readFileString(manifestPath).pipe(Effect.mapError((cause) => new SourceNotResolvable({
65
+ category: "validation",
66
+ detail: `AXM manifest could not be read: ${manifestPath}`,
67
+ cause,
68
+ })));
69
+ const raw = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(text).pipe(Effect.mapError((cause) => new SourceNotResolvable({
70
+ category: "validation",
71
+ detail: `AXM manifest contains invalid JSON: ${manifestPath}`,
72
+ cause,
73
+ })));
74
+ yield* Effect.fromResult(validateManifestHasNoAgentsField(manifestFile, raw)).pipe(Effect.mapError((cause) => new SourceNotResolvable({ category: "validation", detail: cause.detail, cause })));
75
+ yield* Schema.decodeUnknownEffect(manifestSchemaForType(type))(raw).pipe(Effect.mapError((cause) => new SourceNotResolvable({
76
+ category: "validation",
77
+ detail: `AXM manifest does not conform to ${manifestFile}: ${manifestPath}`,
78
+ cause,
79
+ })));
80
+ const identity = yield* Schema.decodeUnknownEffect(ManifestIdentitySchema)(raw).pipe(Effect.mapError((cause) => new SourceNotResolvable({
81
+ category: "validation",
82
+ detail: `AXM manifest identity is invalid: ${manifestPath}`,
83
+ cause,
84
+ })));
85
+ if (identity.type !== type || manifestFilenameForType(identity.type) !== manifestFile) {
86
+ return yield* new SourceNotResolvable({
87
+ category: "validation",
88
+ detail: `AXM manifest filename and declared type disagree: ${manifestPath}`,
89
+ });
90
+ }
91
+ return { directory, identity };
92
+ });
93
+ export const discoverExtensionPackages = (root, filter) => Effect.gen(function* () {
94
+ const fs = yield* FileSystem.FileSystem;
95
+ const path = yield* Path.Path;
96
+ const scan = (directory, depth) => Effect.gen(function* () {
97
+ if (depth > DISCOVERY_MAX_DEPTH)
98
+ return [];
99
+ const entries = yield* fs.readDirectory(directory).pipe(Effect.mapError((cause) => new SourceNotResolvable({
100
+ category: "validation",
101
+ detail: `Extension source directory could not be read: ${directory}`,
102
+ cause,
103
+ })));
104
+ const manifests = entries.filter((entry) => typeForManifestFilename(entry) !== undefined);
105
+ if (manifests.length > 0) {
106
+ const candidate = yield* inspectExtensionPackage(directory).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path));
107
+ return matchesFilter(candidate.identity, filter) ? [candidate] : [];
108
+ }
109
+ if (depth === DISCOVERY_MAX_DEPTH)
110
+ return [];
111
+ const children = yield* Effect.forEach(entries.filter((entry) => !DISCOVERY_SKIPPED_DIRECTORIES.has(entry)).sort(), (entry) => Effect.gen(function* () {
112
+ const child = path.join(directory, entry);
113
+ const link = yield* fs.readLink(child).pipe(Effect.option);
114
+ if (Option.isSome(link))
115
+ return [];
116
+ const info = yield* fs.stat(child).pipe(Effect.option);
117
+ if (Option.isNone(info) || info.value.type !== "Directory")
118
+ return [];
119
+ return yield* scan(child, depth + 1);
120
+ }), { concurrency: 16 });
121
+ return children.flat();
122
+ });
123
+ const exists = yield* fs.exists(root).pipe(Effect.mapError((cause) => new SourceNotResolvable({
124
+ category: "validation",
125
+ detail: `Source does not exist: ${root}`,
126
+ cause,
127
+ })));
128
+ if (!exists) {
129
+ return yield* new SourceNotResolvable({
130
+ category: "not_found",
131
+ detail: `Source does not exist: ${root}`,
132
+ });
133
+ }
134
+ const packages = yield* scan(path.resolve(root), 0);
135
+ return [...packages].sort((left, right) => left.directory.localeCompare(right.directory));
136
+ });
137
+ //# sourceMappingURL=package-discovery.js.map
@@ -0,0 +1,25 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as FileSystem from "effect/FileSystem";
3
+ import * as Path from "effect/Path";
4
+ import type * as Scope from "effect/Scope";
5
+ import { type SourceResolutionFailure } from "./errors.js";
6
+ import type { Source } from "@agentxm/extension-model/unstable/sources/types";
7
+ import { SourceHostProviders } from "./service.js";
8
+ import { type DiscoveredExtensionPackage, type ExtensionPackageFilter } from "./package-discovery.js";
9
+ export interface ResolvedExtensionPackage extends DiscoveredExtensionPackage {
10
+ readonly origin: string;
11
+ }
12
+ export interface AcquiredExternalSource {
13
+ readonly directory: string;
14
+ readonly origin: string;
15
+ }
16
+ /** Acquire a stable local view of a local or Git source for the current scope. */
17
+ export declare const acquireExternalSource: (source: Source) => Effect.Effect<AcquiredExternalSource, SourceResolutionFailure, FileSystem.FileSystem | Path.Path | SourceHostProviders | Scope.Scope>;
18
+ /**
19
+ * Discover only manifest-backed AXM packages from a resolved source.
20
+ *
21
+ * Native convention discovery intentionally remains separate so callers can
22
+ * never mistake unmanaged content for a forkable AXM package.
23
+ */
24
+ export declare const findExtensionPackagesFromSource: (source: Source, filter: ExtensionPackageFilter) => Effect.Effect<ReadonlyArray<ResolvedExtensionPackage>, SourceResolutionFailure, FileSystem.FileSystem | Path.Path | SourceHostProviders | Scope.Scope>;
25
+ //# sourceMappingURL=package-sources.d.ts.map
@@ -0,0 +1,102 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as FileSystem from "effect/FileSystem";
3
+ import * as Option from "effect/Option";
4
+ import * as Path from "effect/Path";
5
+ import { SourceNetworkFailure, SourceNotResolvable, } from "./errors.js";
6
+ import { shallowClone } from "./git/operations.js";
7
+ import { buildCloneUrlForSource } from "./providers/git-hosting.js";
8
+ import { SourceHostProviders } from "./service.js";
9
+ import { discoverExtensionPackages, inspectExtensionPackage, } from "./package-discovery.js";
10
+ const acquireClone = (cloneUrl, ref) => Effect.gen(function* () {
11
+ const fs = yield* FileSystem.FileSystem;
12
+ const tempDir = yield* Effect.acquireRelease(fs.makeTempDirectory({ prefix: "axm-source-clone-" }).pipe(Effect.mapError((cause) => new SourceNetworkFailure({
13
+ detail: "Temporary package source directory could not be created",
14
+ cause,
15
+ }))), (directory) => fs.remove(directory, { recursive: true }).pipe(Effect.ignore));
16
+ yield* shallowClone(cloneUrl, tempDir, Option.getOrUndefined(ref));
17
+ return tempDir;
18
+ });
19
+ /** Acquire a stable local view of a local or Git source for the current scope. */
20
+ export const acquireExternalSource = (source) => Effect.gen(function* () {
21
+ const path = yield* Path.Path;
22
+ const providers = yield* SourceHostProviders;
23
+ const origin = providers.origin(source);
24
+ switch (source.type) {
25
+ case "local":
26
+ return { directory: source.path, origin };
27
+ case "git":
28
+ return { directory: yield* acquireClone(source.url.href, source.ref), origin };
29
+ case "github":
30
+ case "gitlab":
31
+ case "bitbucket":
32
+ case "azurerepos": {
33
+ const cloneRoot = yield* acquireClone(buildCloneUrlForSource(source), source.ref);
34
+ return {
35
+ directory: Option.match(source.subPath, {
36
+ onNone: () => cloneRoot,
37
+ onSome: (subPath) => path.join(cloneRoot, subPath),
38
+ }),
39
+ origin,
40
+ };
41
+ }
42
+ case "registry":
43
+ case "workspace":
44
+ return yield* new SourceNotResolvable({
45
+ category: "validation",
46
+ detail: "Native import accepts local or Git sources; use fork for managed AXM sources",
47
+ });
48
+ }
49
+ });
50
+ /**
51
+ * Discover only manifest-backed AXM packages from a resolved source.
52
+ *
53
+ * Native convention discovery intentionally remains separate so callers can
54
+ * never mistake unmanaged content for a forkable AXM package.
55
+ */
56
+ export const findExtensionPackagesFromSource = (source, filter) => Effect.gen(function* () {
57
+ const path = yield* Path.Path;
58
+ const providers = yield* SourceHostProviders;
59
+ const origin = providers.origin(source);
60
+ switch (source.type) {
61
+ case "local": {
62
+ const packages = yield* discoverExtensionPackages(source.path, filter);
63
+ return packages.map((candidate) => ({ ...candidate, origin }));
64
+ }
65
+ case "git": {
66
+ const cloneRoot = yield* acquireClone(source.url.href, source.ref);
67
+ const packages = yield* discoverExtensionPackages(cloneRoot, filter);
68
+ return packages.map((candidate) => ({ ...candidate, origin }));
69
+ }
70
+ case "github":
71
+ case "gitlab":
72
+ case "bitbucket":
73
+ case "azurerepos": {
74
+ const cloneRoot = yield* acquireClone(buildCloneUrlForSource(source), source.ref);
75
+ const discoveryRoot = Option.match(source.subPath, {
76
+ onNone: () => cloneRoot,
77
+ onSome: (subPath) => path.join(cloneRoot, subPath),
78
+ });
79
+ const packages = yield* discoverExtensionPackages(discoveryRoot, filter);
80
+ return packages.map((candidate) => ({ ...candidate, origin }));
81
+ }
82
+ case "registry": {
83
+ const refs = yield* providers.find(source, {
84
+ names: filter.names,
85
+ owner: filter.owner,
86
+ type: filter.type,
87
+ versionRange: Option.none(),
88
+ });
89
+ return yield* Effect.forEach(refs, (ref) => Effect.gen(function* () {
90
+ const files = yield* providers.fetch(ref);
91
+ const candidate = yield* inspectExtensionPackage(files.directory);
92
+ return { ...candidate, origin };
93
+ }), { concurrency: 8 });
94
+ }
95
+ case "workspace":
96
+ return yield* new SourceNotResolvable({
97
+ category: "validation",
98
+ detail: "Workspace packages resolve from their canonical managed path",
99
+ });
100
+ }
101
+ });
102
+ //# sourceMappingURL=package-sources.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Azure Repos source parsing.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ * @packageDocumentation
6
+ */
7
+ export { checkAzureReposRepoExists } from "./repo-exists.js";
8
+ export { parseUrl } from "./url.js";
9
+ export { parseScp } from "./scp.js";
10
+ export { parseShorthand } from "./shorthand.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Azure Repos source parsing.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ * @packageDocumentation
6
+ */
7
+ export { checkAzureReposRepoExists } from "./repo-exists.js";
8
+ export { parseUrl } from "./url.js";
9
+ export { parseScp } from "./scp.js";
10
+ export { parseShorthand } from "./shorthand.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,5 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as HttpClient from "effect/unstable/http/HttpClient";
3
+ import { SourceNotResolvable } from "../../errors.js";
4
+ export declare const checkAzureReposRepoExists: (organization: string, project: string, repo: string) => Effect.Effect<void, SourceNotResolvable, HttpClient.HttpClient>;
5
+ //# sourceMappingURL=repo-exists.d.ts.map
@@ -0,0 +1,21 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as HttpClient from "effect/unstable/http/HttpClient";
3
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
4
+ import { SourceNotResolvable } from "../../errors.js";
5
+ export const checkAzureReposRepoExists = (organization, project, repo) => Effect.gen(function* () {
6
+ const client = yield* HttpClient.HttpClient;
7
+ const url = `https://dev.azure.com/${organization}/${project}/_git/${repo}`;
8
+ const request = HttpClientRequest.head(url);
9
+ const response = yield* client.execute(request).pipe(Effect.mapError((error) => new SourceNotResolvable({
10
+ category: "validation",
11
+ detail: `Failed to check Azure Repos: ${error instanceof Error ? error.message : String(error)}`,
12
+ cause: error,
13
+ })));
14
+ if (response.status < 200 || response.status >= 300) {
15
+ return yield* new SourceNotResolvable({
16
+ category: "validation",
17
+ detail: `Not found on Azure Repos`,
18
+ });
19
+ }
20
+ });
21
+ //# sourceMappingURL=repo-exists.js.map
@@ -0,0 +1,12 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { SourceSyntaxInvalid } from "../../errors.js";
3
+ export declare const parseScp: (input: string, hostname?: string) => Effect.Effect<never, SourceSyntaxInvalid, never> | Effect.Effect<{
4
+ readonly type: "azurerepos";
5
+ readonly repo: string;
6
+ readonly ref: import("effect/Option").Option<string>;
7
+ readonly subPath: import("effect/Option").Option<string>;
8
+ readonly organization: string;
9
+ readonly project: string;
10
+ readonly sourceName?: string | undefined;
11
+ }, never, never>;
12
+ //# sourceMappingURL=scp.d.ts.map
@@ -0,0 +1,29 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Result from "effect/Result";
3
+ import * as Schema from "effect/Schema";
4
+ import { SourceSyntaxInvalid } from "../../errors.js";
5
+ import { AzureReposSourceParamsSchema, } from "@agentxm/extension-model/unstable/sources/types";
6
+ const CANONICAL_SSH_HOSTNAME = "ssh.dev.azure.com";
7
+ /** Matches: git@{hostname}:v3/{org}/{project}/{repo} */
8
+ const SCP_PATTERN = /^git@([^:]+):v3\/([^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?$/;
9
+ const decodeAzureReposSourceParams = Schema.decodeUnknownResult(AzureReposSourceParamsSchema);
10
+ export const parseScp = (input, hostname = CANONICAL_SSH_HOSTNAME) => {
11
+ const match = input.match(SCP_PATTERN);
12
+ if (!match || !match[1] || !match[2] || !match[3] || !match[4] || match[1] !== hostname) {
13
+ return Effect.fail(new SourceSyntaxInvalid({
14
+ detail: "Invalid Azure Repos SSH URL format",
15
+ }));
16
+ }
17
+ const decoded = decodeAzureReposSourceParams({
18
+ type: "azurerepos",
19
+ organization: match[2],
20
+ project: match[3],
21
+ repo: match[4],
22
+ });
23
+ return Result.isSuccess(decoded)
24
+ ? Effect.succeed(decoded.success)
25
+ : Effect.fail(new SourceSyntaxInvalid({
26
+ detail: "Invalid Azure Repos SSH URL format",
27
+ }));
28
+ };
29
+ //# sourceMappingURL=scp.js.map
@@ -0,0 +1,12 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { SourceSyntaxInvalid } from "../../errors.js";
3
+ export declare const parseShorthand: (input: string) => Effect.Effect<never, SourceSyntaxInvalid, never> | Effect.Effect<{
4
+ readonly type: "azurerepos";
5
+ readonly repo: string;
6
+ readonly ref: import("effect/Option").Option<string>;
7
+ readonly subPath: import("effect/Option").Option<string>;
8
+ readonly organization: string;
9
+ readonly project: string;
10
+ readonly sourceName?: string | undefined;
11
+ }, never, never>;
12
+ //# sourceMappingURL=shorthand.d.ts.map
@@ -0,0 +1,45 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Result from "effect/Result";
3
+ import * as Schema from "effect/Schema";
4
+ import { SourceSyntaxInvalid } from "../../errors.js";
5
+ import { AzureReposSourceParamsSchema, } from "@agentxm/extension-model/unstable/sources/types";
6
+ const decode = Schema.decodeUnknownResult(AzureReposSourceParamsSchema);
7
+ export const parseShorthand = (input) => {
8
+ const colon = input.indexOf(":");
9
+ const body = colon < 0 ? input : input.slice(colon + 1);
10
+ const refIndex = body.lastIndexOf("@");
11
+ const coordinate = refIndex > 0 ? body.slice(0, refIndex) : body;
12
+ const ref = refIndex > 0 ? body.slice(refIndex + 1) : undefined;
13
+ const subPathIndex = coordinate.indexOf("//");
14
+ const repositoryCoordinate = subPathIndex < 0 ? coordinate : coordinate.slice(0, subPathIndex);
15
+ const subPath = subPathIndex < 0 ? undefined : coordinate.slice(subPathIndex + 2);
16
+ const [organization, project, repo, ...extra] = repositoryCoordinate.split("/");
17
+ if (organization === undefined ||
18
+ project === undefined ||
19
+ repo === undefined ||
20
+ extra.length > 0 ||
21
+ organization.length === 0 ||
22
+ project.length === 0 ||
23
+ repo.length === 0 ||
24
+ subPath === "" ||
25
+ ref === "") {
26
+ return Effect.fail(new SourceSyntaxInvalid({
27
+ detail: `Invalid Azure Repos shorthand "${input}": expected organization/project/repo[//subpath][@ref]`,
28
+ }));
29
+ }
30
+ const decoded = decode({
31
+ type: "azurerepos",
32
+ organization,
33
+ project,
34
+ repo,
35
+ ...(subPath === undefined ? {} : { subPath }),
36
+ ...(ref === undefined ? {} : { ref }),
37
+ });
38
+ return Result.isSuccess(decoded)
39
+ ? Effect.succeed(decoded.success)
40
+ : Effect.fail(new SourceSyntaxInvalid({
41
+ detail: `Invalid Azure Repos shorthand "${input}"`,
42
+ cause: decoded.failure,
43
+ }));
44
+ };
45
+ //# sourceMappingURL=shorthand.js.map
@@ -0,0 +1,14 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import { SourceSyntaxInvalid } from "../../errors.js";
4
+ export declare const CANONICAL_HOSTNAME = "dev.azure.com";
5
+ export declare const parseUrl: (url: URL, hostname?: string) => Effect.Effect<never, SourceSyntaxInvalid, never> | Effect.Effect<{
6
+ readonly type: "azurerepos";
7
+ readonly repo: string;
8
+ readonly ref: Option.Option<string>;
9
+ readonly subPath: Option.Option<string>;
10
+ readonly organization: string;
11
+ readonly project: string;
12
+ readonly sourceName?: string | undefined;
13
+ }, never, never>;
14
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1,38 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import * as Result from "effect/Result";
4
+ import * as Schema from "effect/Schema";
5
+ import { SourceSyntaxInvalid } from "../../errors.js";
6
+ import { AzureReposSourceParamsSchema, } from "@agentxm/extension-model/unstable/sources/types";
7
+ import { refFromUrlHash } from "../../url-fragment.js";
8
+ export const CANONICAL_HOSTNAME = "dev.azure.com";
9
+ /** Matches: /{org}/{project}/_git/{repo} */
10
+ const AZUREREPOS_PATH_PATTERN = /^\/([^/]+)\/([^/]+)\/_git\/([^/]+?)(?:\.git)?$/;
11
+ const decodeAzureReposSourceParams = Schema.decodeUnknownResult(AzureReposSourceParamsSchema);
12
+ export const parseUrl = (url, hostname = CANONICAL_HOSTNAME) => {
13
+ if (url.hostname !== hostname) {
14
+ return Effect.fail(new SourceSyntaxInvalid({
15
+ detail: "Invalid Azure Repos URL format",
16
+ }));
17
+ }
18
+ const match = url.pathname.match(AZUREREPOS_PATH_PATTERN);
19
+ if (!match || !match[1] || !match[2] || !match[3]) {
20
+ return Effect.fail(new SourceSyntaxInvalid({
21
+ detail: "Invalid Azure Repos URL format",
22
+ }));
23
+ }
24
+ const fragmentRef = Option.getOrUndefined(refFromUrlHash(url));
25
+ const decoded = decodeAzureReposSourceParams({
26
+ type: "azurerepos",
27
+ organization: match[1],
28
+ project: match[2],
29
+ repo: match[3],
30
+ ...(fragmentRef === undefined ? {} : { ref: fragmentRef }),
31
+ });
32
+ return Result.isSuccess(decoded)
33
+ ? Effect.succeed(decoded.success)
34
+ : Effect.fail(new SourceSyntaxInvalid({
35
+ detail: "Invalid Azure Repos URL format",
36
+ }));
37
+ };
38
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Bitbucket source parsing.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ * @packageDocumentation
6
+ */
7
+ export { resolveRepo } from "./resolve-repo.js";
8
+ export { parseShorthand } from "./shorthand.js";
9
+ export { parseUrl } from "./url.js";
10
+ export { parseScp } from "./scp.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Bitbucket source parsing.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ * @packageDocumentation
6
+ */
7
+ export { resolveRepo } from "./resolve-repo.js";
8
+ export { parseShorthand } from "./shorthand.js";
9
+ export { parseUrl } from "./url.js";
10
+ export { parseScp } from "./scp.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,11 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import * as HttpClient from "effect/unstable/http/HttpClient";
4
+ import { SourceNotResolvable } from "../../errors.js";
5
+ import type { BitbucketSourceParams } from "@agentxm/extension-model/unstable/sources/types";
6
+ export declare const resolveRepo: (args: {
7
+ readonly owner: string;
8
+ readonly repo: string;
9
+ readonly subPath: Option.Option<string>;
10
+ }) => Effect.Effect<Option.Option<BitbucketSourceParams>, SourceNotResolvable, HttpClient.HttpClient>;
11
+ //# sourceMappingURL=resolve-repo.d.ts.map
@@ -0,0 +1,33 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import * as HttpClient from "effect/unstable/http/HttpClient";
4
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
5
+ import { SourceNotResolvable } from "../../errors.js";
6
+ const headRequest = (url, _input) => Effect.gen(function* () {
7
+ const client = yield* HttpClient.HttpClient;
8
+ return yield* client.execute(HttpClientRequest.head(url)).pipe(Effect.mapError((error) => new SourceNotResolvable({
9
+ category: "validation",
10
+ detail: `Failed to check Bitbucket: ${error instanceof Error ? error.message : String(error)}`,
11
+ cause: error,
12
+ })));
13
+ });
14
+ export const resolveRepo = (args) => Effect.gen(function* () {
15
+ const repoUrl = `https://bitbucket.org/${args.owner}/${args.repo}`;
16
+ const repoResponse = yield* headRequest(repoUrl, `${args.owner}/${args.repo}`);
17
+ if (repoResponse.status !== 200)
18
+ return Option.none();
19
+ if (Option.isSome(args.subPath)) {
20
+ const subPathUrl = `${repoUrl}/src/HEAD/${args.subPath.value}`;
21
+ const subPathResponse = yield* headRequest(subPathUrl, `${args.owner}/${args.repo}/${args.subPath.value}`);
22
+ if (subPathResponse.status !== 200)
23
+ return Option.none();
24
+ }
25
+ return Option.some({
26
+ type: "bitbucket",
27
+ owner: args.owner,
28
+ repo: args.repo,
29
+ ref: Option.none(),
30
+ subPath: args.subPath,
31
+ });
32
+ });
33
+ //# sourceMappingURL=resolve-repo.js.map
@@ -0,0 +1,11 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { SourceSyntaxInvalid } from "../../errors.js";
3
+ export declare const parseScp: (input: string, hostname?: string) => Effect.Effect<never, SourceSyntaxInvalid, never> | Effect.Effect<{
4
+ readonly owner: string;
5
+ readonly type: "bitbucket";
6
+ readonly repo: string;
7
+ readonly ref: import("effect/Option").Option<string>;
8
+ readonly subPath: import("effect/Option").Option<string>;
9
+ readonly sourceName?: string | undefined;
10
+ }, never, never>;
11
+ //# sourceMappingURL=scp.d.ts.map
@@ -0,0 +1,28 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Result from "effect/Result";
3
+ import * as Schema from "effect/Schema";
4
+ import { SourceSyntaxInvalid } from "../../errors.js";
5
+ import { BitbucketSourceParamsSchema, } from "@agentxm/extension-model/unstable/sources/types";
6
+ import { CANONICAL_HOSTNAME } from "./url.js";
7
+ /** Matches: git@{hostname}:owner/repo.git */
8
+ const SCP_PATTERN = /^git@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/;
9
+ const decodeBitbucketSourceParams = Schema.decodeUnknownResult(BitbucketSourceParamsSchema);
10
+ export const parseScp = (input, hostname = CANONICAL_HOSTNAME) => {
11
+ const match = input.match(SCP_PATTERN);
12
+ if (!match || !match[1] || !match[2] || !match[3] || match[1] !== hostname) {
13
+ return Effect.fail(new SourceSyntaxInvalid({
14
+ detail: "Invalid Bitbucket SSH URL format",
15
+ }));
16
+ }
17
+ const decoded = decodeBitbucketSourceParams({
18
+ type: "bitbucket",
19
+ owner: match[2],
20
+ repo: match[3],
21
+ });
22
+ return Result.isSuccess(decoded)
23
+ ? Effect.succeed(decoded.success)
24
+ : Effect.fail(new SourceSyntaxInvalid({
25
+ detail: "Invalid Bitbucket SSH URL format",
26
+ }));
27
+ };
28
+ //# sourceMappingURL=scp.js.map
@@ -0,0 +1,10 @@
1
+ import * as Effect from "effect/Effect";
2
+ export declare const parseShorthand: (input: string) => Effect.Effect<{
3
+ owner: string;
4
+ repo: string;
5
+ ref: import("effect/Option").Option<string>;
6
+ subPath: import("effect/Option").Option<string>;
7
+ sourceName?: string | undefined;
8
+ type: "bitbucket";
9
+ }, import("../../errors.ts").SourceSyntaxInvalid, never>;
10
+ //# sourceMappingURL=shorthand.d.ts.map
@@ -0,0 +1,11 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { parseProviderShorthand } from "../parse-provider-shorthand.js";
3
+ export const parseShorthand = (input) => Effect.gen(function* () {
4
+ const body = input.slice("bitbucket:".length);
5
+ const parts = yield* parseProviderShorthand(body, input);
6
+ return {
7
+ type: "bitbucket",
8
+ ...parts,
9
+ };
10
+ });
11
+ //# sourceMappingURL=shorthand.js.map
@@ -0,0 +1,13 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
3
+ import { SourceSyntaxInvalid } from "../../errors.js";
4
+ export declare const CANONICAL_HOSTNAME = "bitbucket.org";
5
+ export declare const parseUrl: (url: URL, hostname?: string) => Effect.Effect<never, SourceSyntaxInvalid, never> | Effect.Effect<{
6
+ readonly owner: string;
7
+ readonly type: "bitbucket";
8
+ readonly repo: string;
9
+ readonly ref: Option.Option<string>;
10
+ readonly subPath: Option.Option<string>;
11
+ readonly sourceName?: string | undefined;
12
+ }, never, never>;
13
+ //# sourceMappingURL=url.d.ts.map