@herdctl/core 5.5.0 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/__tests__/merge.test.js +1 -1
- package/dist/config/__tests__/merge.test.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +10 -2
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +6 -2
- package/dist/config/schema.js.map +1 -1
- package/dist/distribution/__tests__/agent-discovery.test.d.ts +7 -0
- package/dist/distribution/__tests__/agent-discovery.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/agent-discovery.test.js +443 -0
- package/dist/distribution/__tests__/agent-discovery.test.js.map +1 -0
- package/dist/distribution/__tests__/agent-info.test.d.ts +7 -0
- package/dist/distribution/__tests__/agent-info.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/agent-info.test.js +568 -0
- package/dist/distribution/__tests__/agent-info.test.js.map +1 -0
- package/dist/distribution/__tests__/agent-remover.test.d.ts +7 -0
- package/dist/distribution/__tests__/agent-remover.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/agent-remover.test.js +498 -0
- package/dist/distribution/__tests__/agent-remover.test.js.map +1 -0
- package/dist/distribution/__tests__/agent-repo-metadata.test.d.ts +5 -0
- package/dist/distribution/__tests__/agent-repo-metadata.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/agent-repo-metadata.test.js +500 -0
- package/dist/distribution/__tests__/agent-repo-metadata.test.js.map +1 -0
- package/dist/distribution/__tests__/env-scanner.test.d.ts +5 -0
- package/dist/distribution/__tests__/env-scanner.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/env-scanner.test.js +576 -0
- package/dist/distribution/__tests__/env-scanner.test.js.map +1 -0
- package/dist/distribution/__tests__/file-installer.test.d.ts +7 -0
- package/dist/distribution/__tests__/file-installer.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/file-installer.test.js +714 -0
- package/dist/distribution/__tests__/file-installer.test.js.map +1 -0
- package/dist/distribution/__tests__/fleet-config-updater.test.d.ts +7 -0
- package/dist/distribution/__tests__/fleet-config-updater.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/fleet-config-updater.test.js +531 -0
- package/dist/distribution/__tests__/fleet-config-updater.test.js.map +1 -0
- package/dist/distribution/__tests__/installation-metadata.test.d.ts +2 -0
- package/dist/distribution/__tests__/installation-metadata.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/installation-metadata.test.js +292 -0
- package/dist/distribution/__tests__/installation-metadata.test.js.map +1 -0
- package/dist/distribution/__tests__/integration.test.d.ts +10 -0
- package/dist/distribution/__tests__/integration.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/integration.test.js +522 -0
- package/dist/distribution/__tests__/integration.test.js.map +1 -0
- package/dist/distribution/__tests__/repository-fetcher.test.d.ts +5 -0
- package/dist/distribution/__tests__/repository-fetcher.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/repository-fetcher.test.js +386 -0
- package/dist/distribution/__tests__/repository-fetcher.test.js.map +1 -0
- package/dist/distribution/__tests__/repository-validator.test.d.ts +7 -0
- package/dist/distribution/__tests__/repository-validator.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/repository-validator.test.js +447 -0
- package/dist/distribution/__tests__/repository-validator.test.js.map +1 -0
- package/dist/distribution/__tests__/source-specifier.test.d.ts +5 -0
- package/dist/distribution/__tests__/source-specifier.test.d.ts.map +1 -0
- package/dist/distribution/__tests__/source-specifier.test.js +533 -0
- package/dist/distribution/__tests__/source-specifier.test.js.map +1 -0
- package/dist/distribution/agent-discovery.d.ts +81 -0
- package/dist/distribution/agent-discovery.d.ts.map +1 -0
- package/dist/distribution/agent-discovery.js +264 -0
- package/dist/distribution/agent-discovery.js.map +1 -0
- package/dist/distribution/agent-info.d.ts +86 -0
- package/dist/distribution/agent-info.d.ts.map +1 -0
- package/dist/distribution/agent-info.js +225 -0
- package/dist/distribution/agent-info.js.map +1 -0
- package/dist/distribution/agent-remover.d.ts +83 -0
- package/dist/distribution/agent-remover.d.ts.map +1 -0
- package/dist/distribution/agent-remover.js +222 -0
- package/dist/distribution/agent-remover.js.map +1 -0
- package/dist/distribution/agent-repo-metadata.d.ts +181 -0
- package/dist/distribution/agent-repo-metadata.d.ts.map +1 -0
- package/dist/distribution/agent-repo-metadata.js +143 -0
- package/dist/distribution/agent-repo-metadata.js.map +1 -0
- package/dist/distribution/env-scanner.d.ts +78 -0
- package/dist/distribution/env-scanner.d.ts.map +1 -0
- package/dist/distribution/env-scanner.js +144 -0
- package/dist/distribution/env-scanner.js.map +1 -0
- package/dist/distribution/file-installer.d.ts +80 -0
- package/dist/distribution/file-installer.d.ts.map +1 -0
- package/dist/distribution/file-installer.js +268 -0
- package/dist/distribution/file-installer.js.map +1 -0
- package/dist/distribution/fleet-config-updater.d.ts +96 -0
- package/dist/distribution/fleet-config-updater.d.ts.map +1 -0
- package/dist/distribution/fleet-config-updater.js +266 -0
- package/dist/distribution/fleet-config-updater.js.map +1 -0
- package/dist/distribution/index.d.ts +23 -0
- package/dist/distribution/index.d.ts.map +1 -0
- package/dist/distribution/index.js +42 -0
- package/dist/distribution/index.js.map +1 -0
- package/dist/distribution/installation-metadata.d.ts +191 -0
- package/dist/distribution/installation-metadata.d.ts.map +1 -0
- package/dist/distribution/installation-metadata.js +100 -0
- package/dist/distribution/installation-metadata.js.map +1 -0
- package/dist/distribution/repository-fetcher.d.ts +104 -0
- package/dist/distribution/repository-fetcher.d.ts.map +1 -0
- package/dist/distribution/repository-fetcher.js +246 -0
- package/dist/distribution/repository-fetcher.js.map +1 -0
- package/dist/distribution/repository-validator.d.ts +86 -0
- package/dist/distribution/repository-validator.d.ts.map +1 -0
- package/dist/distribution/repository-validator.js +296 -0
- package/dist/distribution/repository-validator.js.map +1 -0
- package/dist/distribution/source-specifier.d.ts +106 -0
- package/dist/distribution/source-specifier.d.ts.map +1 -0
- package/dist/distribution/source-specifier.js +247 -0
- package/dist/distribution/source-specifier.js.map +1 -0
- package/dist/fleet-manager/errors.d.ts +15 -0
- package/dist/fleet-manager/errors.d.ts.map +1 -1
- package/dist/fleet-manager/errors.js +16 -0
- package/dist/fleet-manager/errors.js.map +1 -1
- package/dist/fleet-manager/fleet-manager.d.ts.map +1 -1
- package/dist/fleet-manager/fleet-manager.js +31 -9
- package/dist/fleet-manager/fleet-manager.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/runner/message-processor.d.ts.map +1 -1
- package/dist/runner/message-processor.js +7 -2
- package/dist/runner/message-processor.js.map +1 -1
- package/dist/runner/runtime/container-manager.js +1 -1
- package/dist/runner/runtime/container-manager.js.map +1 -1
- package/dist/scheduler/errors.d.ts +15 -0
- package/dist/scheduler/errors.d.ts.map +1 -1
- package/dist/scheduler/schedule-runner.d.ts.map +1 -1
- package/dist/scheduler/schedule-runner.js +6 -5
- package/dist/scheduler/schedule-runner.js.map +1 -1
- package/dist/state/__tests__/jsonl-parser.test.d.ts +5 -0
- package/dist/state/__tests__/jsonl-parser.test.d.ts.map +1 -0
- package/dist/state/__tests__/jsonl-parser.test.js +307 -0
- package/dist/state/__tests__/jsonl-parser.test.js.map +1 -0
- package/dist/state/__tests__/session-attribution.test.d.ts +2 -0
- package/dist/state/__tests__/session-attribution.test.d.ts.map +1 -0
- package/dist/state/__tests__/session-attribution.test.js +567 -0
- package/dist/state/__tests__/session-attribution.test.js.map +1 -0
- package/dist/state/__tests__/session-discovery.test.d.ts +2 -0
- package/dist/state/__tests__/session-discovery.test.d.ts.map +1 -0
- package/dist/state/__tests__/session-discovery.test.js +941 -0
- package/dist/state/__tests__/session-discovery.test.js.map +1 -0
- package/dist/state/__tests__/session-metadata.test.d.ts +2 -0
- package/dist/state/__tests__/session-metadata.test.d.ts.map +1 -0
- package/dist/state/__tests__/session-metadata.test.js +422 -0
- package/dist/state/__tests__/session-metadata.test.js.map +1 -0
- package/dist/state/__tests__/tool-parsing.test.d.ts +5 -0
- package/dist/state/__tests__/tool-parsing.test.d.ts.map +1 -0
- package/dist/state/__tests__/tool-parsing.test.js +315 -0
- package/dist/state/__tests__/tool-parsing.test.js.map +1 -0
- package/dist/state/index.d.ts +5 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +10 -0
- package/dist/state/index.js.map +1 -1
- package/dist/state/jsonl-parser.d.ts +115 -0
- package/dist/state/jsonl-parser.d.ts.map +1 -0
- package/dist/state/jsonl-parser.js +437 -0
- package/dist/state/jsonl-parser.js.map +1 -0
- package/dist/state/session-attribution.d.ts +35 -0
- package/dist/state/session-attribution.d.ts.map +1 -0
- package/dist/state/session-attribution.js +179 -0
- package/dist/state/session-attribution.js.map +1 -0
- package/dist/state/session-discovery.d.ts +188 -0
- package/dist/state/session-discovery.d.ts.map +1 -0
- package/dist/state/session-discovery.js +513 -0
- package/dist/state/session-discovery.js.map +1 -0
- package/dist/state/session-metadata.d.ts +186 -0
- package/dist/state/session-metadata.d.ts.map +1 -0
- package/dist/state/session-metadata.js +297 -0
- package/dist/state/session-metadata.js.map +1 -0
- package/dist/state/tool-parsing.d.ts +88 -0
- package/dist/state/tool-parsing.d.ts.map +1 -0
- package/dist/state/tool-parsing.js +199 -0
- package/dist/state/tool-parsing.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installation metadata schema for agent distribution
|
|
3
|
+
*
|
|
4
|
+
* Validates the `metadata.json` file that lives in each installed agent's
|
|
5
|
+
* directory root. This file tracks where an agent was installed from and when.
|
|
6
|
+
*
|
|
7
|
+
* The schema is intentionally extensible (no .strict()) to support future
|
|
8
|
+
* features like agentic initialization without breaking existing installs.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Source Type Schema
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Source types for installed agents
|
|
16
|
+
*
|
|
17
|
+
* - `github`: Installed from a GitHub repository
|
|
18
|
+
* - `local`: Installed from a local filesystem path
|
|
19
|
+
*/
|
|
20
|
+
export const SourceTypeSchema = z.enum(["github", "local"]);
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Source Schema
|
|
23
|
+
// =============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Source information schema
|
|
26
|
+
*
|
|
27
|
+
* Tracks the origin of an installed agent. The `type` field is required,
|
|
28
|
+
* while other fields are optional and depend on the source type:
|
|
29
|
+
*
|
|
30
|
+
* - `url`: The original source URL or path (GitHub URL, local path)
|
|
31
|
+
* - `ref`: Git reference (tag, branch, commit SHA) for GitHub sources
|
|
32
|
+
* - `version`: Version from herdctl.json at install time
|
|
33
|
+
*/
|
|
34
|
+
export const InstallationSourceSchema = z
|
|
35
|
+
.object({
|
|
36
|
+
/** The type of source (github or local) */
|
|
37
|
+
type: SourceTypeSchema,
|
|
38
|
+
/** The original source URL or path */
|
|
39
|
+
url: z.string().optional(),
|
|
40
|
+
/** Git reference (tag, branch, commit) for version-controlled sources */
|
|
41
|
+
ref: z.string().optional(),
|
|
42
|
+
/** Version from herdctl.json at install time */
|
|
43
|
+
version: z.string().optional(),
|
|
44
|
+
})
|
|
45
|
+
.passthrough();
|
|
46
|
+
// =============================================================================
|
|
47
|
+
// ISO 8601 Timestamp Schema
|
|
48
|
+
// =============================================================================
|
|
49
|
+
/**
|
|
50
|
+
* ISO 8601 timestamp pattern
|
|
51
|
+
*
|
|
52
|
+
* Matches formats like:
|
|
53
|
+
* - 2024-01-15T10:30:00Z
|
|
54
|
+
* - 2024-01-15T10:30:00.123Z
|
|
55
|
+
* - 2024-01-15T10:30:00+00:00
|
|
56
|
+
* - 2024-01-15T10:30:00-05:00
|
|
57
|
+
*/
|
|
58
|
+
const ISO8601_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
59
|
+
/**
|
|
60
|
+
* Schema for ISO 8601 formatted timestamps
|
|
61
|
+
*/
|
|
62
|
+
export const ISO8601TimestampSchema = z.string().regex(ISO8601_PATTERN, {
|
|
63
|
+
message: "Timestamp must be in ISO 8601 format (e.g., 2024-01-15T10:30:00Z or 2024-01-15T10:30:00+00:00)",
|
|
64
|
+
});
|
|
65
|
+
// =============================================================================
|
|
66
|
+
// Installation Metadata Schema
|
|
67
|
+
// =============================================================================
|
|
68
|
+
/**
|
|
69
|
+
* Installation metadata schema
|
|
70
|
+
*
|
|
71
|
+
* This schema validates the `metadata.json` file that tracks installation
|
|
72
|
+
* information for each agent. It is intentionally extensible (uses default
|
|
73
|
+
* Zod behavior, not .strict()) to allow adding future fields like
|
|
74
|
+
* `initialization` without breaking existing installs.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```json
|
|
78
|
+
* {
|
|
79
|
+
* "source": {
|
|
80
|
+
* "type": "github",
|
|
81
|
+
* "url": "https://github.com/user/agent-repo",
|
|
82
|
+
* "ref": "v1.0.0",
|
|
83
|
+
* "version": "1.0.0"
|
|
84
|
+
* },
|
|
85
|
+
* "installed_at": "2024-01-15T10:30:00Z",
|
|
86
|
+
* "installed_by": "herdctl@0.5.0"
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export const InstallationMetadataSchema = z
|
|
91
|
+
.object({
|
|
92
|
+
/** Source information - where the agent was installed from */
|
|
93
|
+
source: InstallationSourceSchema,
|
|
94
|
+
/** ISO 8601 timestamp of when the agent was installed */
|
|
95
|
+
installed_at: ISO8601TimestampSchema,
|
|
96
|
+
/** herdctl version that performed the installation (e.g., "herdctl@0.5.0") */
|
|
97
|
+
installed_by: z.string().optional(),
|
|
98
|
+
})
|
|
99
|
+
.passthrough();
|
|
100
|
+
//# sourceMappingURL=installation-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installation-metadata.js","sourceRoot":"","sources":["../../src/distribution/installation-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AAK5D,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC;KACtC,MAAM,CAAC;IACN,2CAA2C;IAC3C,IAAI,EAAE,gBAAgB;IAEtB,sCAAsC;IACtC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE1B,yEAAyE;IACzE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE1B,gDAAgD;IAChD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC;KACD,WAAW,EAAE,CAAC;AAKjB,gFAAgF;AAChF,4BAA4B;AAC5B,gFAAgF;AAEhF;;;;;;;;GAQG;AACH,MAAM,eAAe,GAAG,sEAAsE,CAAC;AAE/F;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE;IACtE,OAAO,EACL,gGAAgG;CACnG,CAAC,CAAC;AAEH,gFAAgF;AAChF,+BAA+B;AAC/B,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC;KACxC,MAAM,CAAC;IACN,8DAA8D;IAC9D,MAAM,EAAE,wBAAwB;IAEhC,yDAAyD;IACzD,YAAY,EAAE,sBAAsB;IAEpC,8EAA8E;IAC9E,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC;KACD,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository fetching for agent distribution
|
|
3
|
+
*
|
|
4
|
+
* Fetches agent repositories from various sources (GitHub, local paths) and
|
|
5
|
+
* provides them in a temporary directory for validation and installation.
|
|
6
|
+
*/
|
|
7
|
+
import { FleetManagerError } from "../fleet-manager/errors.js";
|
|
8
|
+
/**
|
|
9
|
+
* GitHub source specifier
|
|
10
|
+
*/
|
|
11
|
+
export interface GitHubFetchSource {
|
|
12
|
+
type: "github";
|
|
13
|
+
owner: string;
|
|
14
|
+
repo: string;
|
|
15
|
+
ref?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Local filesystem source specifier
|
|
19
|
+
*/
|
|
20
|
+
export interface LocalFetchSource {
|
|
21
|
+
type: "local";
|
|
22
|
+
path: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Union of all fetch source types
|
|
26
|
+
*/
|
|
27
|
+
export type FetchSource = GitHubFetchSource | LocalFetchSource;
|
|
28
|
+
/**
|
|
29
|
+
* Result of fetching a repository
|
|
30
|
+
*
|
|
31
|
+
* Note: Named RepositoryFetchResult to avoid collision with work-sources FetchResult
|
|
32
|
+
*/
|
|
33
|
+
export interface RepositoryFetchResult {
|
|
34
|
+
/** Path to the fetched repository contents */
|
|
35
|
+
path: string;
|
|
36
|
+
/** Cleanup function to remove the temporary directory */
|
|
37
|
+
cleanup: () => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Base error for repository fetching failures
|
|
41
|
+
*/
|
|
42
|
+
export declare class RepositoryFetchError extends FleetManagerError {
|
|
43
|
+
readonly source: FetchSource;
|
|
44
|
+
constructor(message: string, source: FetchSource, cause?: Error);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Error when GitHub authentication fails during clone
|
|
48
|
+
*
|
|
49
|
+
* Note: Named GitHubCloneAuthError to avoid collision with work-sources GitHubAuthError
|
|
50
|
+
*/
|
|
51
|
+
export declare class GitHubCloneAuthError extends RepositoryFetchError {
|
|
52
|
+
constructor(source: GitHubFetchSource, cause?: Error);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Error when a GitHub repository is not found
|
|
56
|
+
*/
|
|
57
|
+
export declare class GitHubRepoNotFoundError extends RepositoryFetchError {
|
|
58
|
+
constructor(source: GitHubFetchSource, cause?: Error);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Error when a network operation fails
|
|
62
|
+
*/
|
|
63
|
+
export declare class NetworkError extends RepositoryFetchError {
|
|
64
|
+
constructor(source: FetchSource, cause?: Error);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Error when a local path doesn't exist or isn't a directory
|
|
68
|
+
*/
|
|
69
|
+
export declare class LocalPathError extends RepositoryFetchError {
|
|
70
|
+
constructor(source: LocalFetchSource, reason: string, cause?: Error);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Fetch a repository from a source specifier
|
|
74
|
+
*
|
|
75
|
+
* Clones or copies the repository to a temporary directory and returns
|
|
76
|
+
* the path along with a cleanup function.
|
|
77
|
+
*
|
|
78
|
+
* @param source - The source specifier (GitHub or local)
|
|
79
|
+
* @returns The path to the fetched repository and a cleanup function
|
|
80
|
+
* @throws {GitHubCloneAuthError} When GitHub authentication fails
|
|
81
|
+
* @throws {GitHubRepoNotFoundError} When the GitHub repository doesn't exist
|
|
82
|
+
* @throws {NetworkError} When a network operation fails
|
|
83
|
+
* @throws {LocalPathError} When the local path is invalid
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const result = await fetchRepository({
|
|
88
|
+
* type: 'github',
|
|
89
|
+
* owner: 'herdctl',
|
|
90
|
+
* repo: 'example-agent',
|
|
91
|
+
* ref: 'v1.0.0'
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* try {
|
|
95
|
+
* // Use result.path to access the repository files
|
|
96
|
+
* const agentYaml = await readFile(join(result.path, 'agent.yaml'));
|
|
97
|
+
* } finally {
|
|
98
|
+
* // Always clean up when done
|
|
99
|
+
* await result.cleanup();
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function fetchRepository(source: FetchSource): Promise<RepositoryFetchResult>;
|
|
104
|
+
//# sourceMappingURL=repository-fetcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-fetcher.d.ts","sourceRoot":"","sources":["../../src/distribution/repository-fetcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAU/D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAMD;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,iBAAiB;aAGvC,MAAM,EAAE,WAAW;gBADnC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,WAAW,EACnC,KAAK,CAAC,EAAE,KAAK;CAKhB;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,oBAAoB;gBAChD,MAAM,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,KAAK;CAUrD;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,oBAAoB;gBACnD,MAAM,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,KAAK;CASrD;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,oBAAoB;gBACxC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,KAAK;CAW/C;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,oBAAoB;gBAC1C,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAIpE;AAgKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAczF"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository fetching for agent distribution
|
|
3
|
+
*
|
|
4
|
+
* Fetches agent repositories from various sources (GitHub, local paths) and
|
|
5
|
+
* provides them in a temporary directory for validation and installation.
|
|
6
|
+
*/
|
|
7
|
+
import { execFile } from "node:child_process";
|
|
8
|
+
import { cp, mkdtemp, rm, stat } from "node:fs/promises";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { promisify } from "node:util";
|
|
12
|
+
import { FleetManagerError } from "../fleet-manager/errors.js";
|
|
13
|
+
import { createLogger } from "../utils/logger.js";
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
const logger = createLogger("distribution");
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Error Classes
|
|
18
|
+
// =============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Base error for repository fetching failures
|
|
21
|
+
*/
|
|
22
|
+
export class RepositoryFetchError extends FleetManagerError {
|
|
23
|
+
source;
|
|
24
|
+
constructor(message, source, cause) {
|
|
25
|
+
super(message, { cause, code: "REPOSITORY_FETCH_ERROR" });
|
|
26
|
+
this.source = source;
|
|
27
|
+
this.name = "RepositoryFetchError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Error when GitHub authentication fails during clone
|
|
32
|
+
*
|
|
33
|
+
* Note: Named GitHubCloneAuthError to avoid collision with work-sources GitHubAuthError
|
|
34
|
+
*/
|
|
35
|
+
export class GitHubCloneAuthError extends RepositoryFetchError {
|
|
36
|
+
constructor(source, cause) {
|
|
37
|
+
super(`Authentication failed for github:${source.owner}/${source.repo}. ` +
|
|
38
|
+
`Make sure your Git credentials are configured correctly. ` +
|
|
39
|
+
`For private repos, set up a GitHub personal access token or SSH key.`, source, cause);
|
|
40
|
+
this.name = "GitHubCloneAuthError";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Error when a GitHub repository is not found
|
|
45
|
+
*/
|
|
46
|
+
export class GitHubRepoNotFoundError extends RepositoryFetchError {
|
|
47
|
+
constructor(source, cause) {
|
|
48
|
+
super(`Repository not found: github:${source.owner}/${source.repo}. ` +
|
|
49
|
+
`Check that the owner and repository name are correct, and that you have access to the repo.`, source, cause);
|
|
50
|
+
this.name = "GitHubRepoNotFoundError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Error when a network operation fails
|
|
55
|
+
*/
|
|
56
|
+
export class NetworkError extends RepositoryFetchError {
|
|
57
|
+
constructor(source, cause) {
|
|
58
|
+
const sourceStr = source.type === "github" ? `github:${source.owner}/${source.repo}` : source.type;
|
|
59
|
+
super(`Network error while fetching ${sourceStr}. ` +
|
|
60
|
+
`Check your internet connection and try again.`, source, cause);
|
|
61
|
+
this.name = "NetworkError";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Error when a local path doesn't exist or isn't a directory
|
|
66
|
+
*/
|
|
67
|
+
export class LocalPathError extends RepositoryFetchError {
|
|
68
|
+
constructor(source, reason, cause) {
|
|
69
|
+
super(`Local source error for "${source.path}": ${reason}`, source, cause);
|
|
70
|
+
this.name = "LocalPathError";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// =============================================================================
|
|
74
|
+
// Implementation
|
|
75
|
+
// =============================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Create a temporary directory for fetching
|
|
78
|
+
*/
|
|
79
|
+
async function createTempDir(prefix) {
|
|
80
|
+
const base = join(tmpdir(), `herdctl-${prefix}-`);
|
|
81
|
+
return mkdtemp(base);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Fetch a repository from GitHub via shallow clone
|
|
85
|
+
*/
|
|
86
|
+
async function fetchFromGitHub(source) {
|
|
87
|
+
const url = `https://github.com/${source.owner}/${source.repo}.git`;
|
|
88
|
+
const tempDir = await createTempDir("github");
|
|
89
|
+
logger.debug("Cloning GitHub repository", {
|
|
90
|
+
owner: source.owner,
|
|
91
|
+
repo: source.repo,
|
|
92
|
+
ref: source.ref,
|
|
93
|
+
tempDir,
|
|
94
|
+
});
|
|
95
|
+
const args = ["clone", "--depth", "1"];
|
|
96
|
+
if (source.ref) {
|
|
97
|
+
args.push("--branch", source.ref);
|
|
98
|
+
}
|
|
99
|
+
args.push(url, tempDir);
|
|
100
|
+
try {
|
|
101
|
+
await execFileAsync("git", args, {
|
|
102
|
+
env: {
|
|
103
|
+
...process.env,
|
|
104
|
+
// Prevent interactive auth prompts from hanging
|
|
105
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
106
|
+
},
|
|
107
|
+
timeout: 120000, // 2 minute timeout
|
|
108
|
+
});
|
|
109
|
+
logger.info("Successfully cloned repository", {
|
|
110
|
+
source: `github:${source.owner}/${source.repo}`,
|
|
111
|
+
ref: source.ref,
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
path: tempDir,
|
|
115
|
+
cleanup: async () => {
|
|
116
|
+
logger.debug("Cleaning up temporary directory", { path: tempDir });
|
|
117
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
// Clean up temp dir on failure
|
|
123
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
124
|
+
/* ignore cleanup errors */
|
|
125
|
+
});
|
|
126
|
+
const error = err;
|
|
127
|
+
const stderr = error.stderr?.toLowerCase() ?? "";
|
|
128
|
+
// Node.js execFile returns exit code as number, but handle string for safety
|
|
129
|
+
const exitCode = typeof error.code === "number" ? error.code : parseInt(String(error.code), 10);
|
|
130
|
+
// Check specific error patterns FIRST before falling back to generic exit code checks.
|
|
131
|
+
// Git exit code 128 is used for multiple failure modes (auth, not found, etc.),
|
|
132
|
+
// so we must check message content to distinguish between them.
|
|
133
|
+
// Check for repository not found errors (specific patterns first)
|
|
134
|
+
if (stderr.includes("repository not found") ||
|
|
135
|
+
stderr.includes("does not exist") ||
|
|
136
|
+
stderr.includes("not found")) {
|
|
137
|
+
throw new GitHubRepoNotFoundError(source, error);
|
|
138
|
+
}
|
|
139
|
+
// Check for network errors
|
|
140
|
+
if (stderr.includes("could not resolve host") ||
|
|
141
|
+
stderr.includes("network") ||
|
|
142
|
+
stderr.includes("connection")) {
|
|
143
|
+
throw new NetworkError(source, error);
|
|
144
|
+
}
|
|
145
|
+
// Check for authentication errors - either explicit auth messages or
|
|
146
|
+
// exit code 128 with credential-related messages
|
|
147
|
+
if (stderr.includes("authentication") ||
|
|
148
|
+
stderr.includes("could not read") ||
|
|
149
|
+
exitCode === 128) {
|
|
150
|
+
throw new GitHubCloneAuthError(source, error);
|
|
151
|
+
}
|
|
152
|
+
// Generic error
|
|
153
|
+
throw new RepositoryFetchError(`Failed to clone github:${source.owner}/${source.repo}: ${error.message}`, source, error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Fetch from a local filesystem path by copying to a temp directory
|
|
158
|
+
*/
|
|
159
|
+
async function fetchFromLocal(source) {
|
|
160
|
+
logger.debug("Copying local directory", { path: source.path });
|
|
161
|
+
// Validate the source path exists
|
|
162
|
+
let stats;
|
|
163
|
+
try {
|
|
164
|
+
stats = await stat(source.path);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
const error = err;
|
|
168
|
+
if (error.code === "ENOENT") {
|
|
169
|
+
throw new LocalPathError(source, "Path does not exist");
|
|
170
|
+
}
|
|
171
|
+
throw new LocalPathError(source, `Cannot access path: ${error.message}`, error);
|
|
172
|
+
}
|
|
173
|
+
// Validate it's a directory
|
|
174
|
+
if (!stats.isDirectory()) {
|
|
175
|
+
throw new LocalPathError(source, "Path is not a directory");
|
|
176
|
+
}
|
|
177
|
+
// Copy to temp directory
|
|
178
|
+
const tempDir = await createTempDir("local");
|
|
179
|
+
try {
|
|
180
|
+
await cp(source.path, tempDir, { recursive: true });
|
|
181
|
+
logger.info("Successfully copied local directory", {
|
|
182
|
+
source: source.path,
|
|
183
|
+
dest: tempDir,
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
path: tempDir,
|
|
187
|
+
cleanup: async () => {
|
|
188
|
+
logger.debug("Cleaning up temporary directory", { path: tempDir });
|
|
189
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
// Clean up temp dir on failure
|
|
195
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
196
|
+
/* ignore cleanup errors */
|
|
197
|
+
});
|
|
198
|
+
const error = err;
|
|
199
|
+
throw new LocalPathError(source, `Failed to copy directory: ${error.message}`, error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Fetch a repository from a source specifier
|
|
204
|
+
*
|
|
205
|
+
* Clones or copies the repository to a temporary directory and returns
|
|
206
|
+
* the path along with a cleanup function.
|
|
207
|
+
*
|
|
208
|
+
* @param source - The source specifier (GitHub or local)
|
|
209
|
+
* @returns The path to the fetched repository and a cleanup function
|
|
210
|
+
* @throws {GitHubCloneAuthError} When GitHub authentication fails
|
|
211
|
+
* @throws {GitHubRepoNotFoundError} When the GitHub repository doesn't exist
|
|
212
|
+
* @throws {NetworkError} When a network operation fails
|
|
213
|
+
* @throws {LocalPathError} When the local path is invalid
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* const result = await fetchRepository({
|
|
218
|
+
* type: 'github',
|
|
219
|
+
* owner: 'herdctl',
|
|
220
|
+
* repo: 'example-agent',
|
|
221
|
+
* ref: 'v1.0.0'
|
|
222
|
+
* });
|
|
223
|
+
*
|
|
224
|
+
* try {
|
|
225
|
+
* // Use result.path to access the repository files
|
|
226
|
+
* const agentYaml = await readFile(join(result.path, 'agent.yaml'));
|
|
227
|
+
* } finally {
|
|
228
|
+
* // Always clean up when done
|
|
229
|
+
* await result.cleanup();
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export async function fetchRepository(source) {
|
|
234
|
+
switch (source.type) {
|
|
235
|
+
case "github":
|
|
236
|
+
return fetchFromGitHub(source);
|
|
237
|
+
case "local":
|
|
238
|
+
return fetchFromLocal(source);
|
|
239
|
+
default: {
|
|
240
|
+
// Exhaustive check
|
|
241
|
+
const _exhaustive = source;
|
|
242
|
+
throw new Error(`Unknown source type: ${_exhaustive.type}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=repository-fetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-fetcher.js","sourceRoot":"","sources":["../../src/distribution/repository-fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository Validation for Agent Distribution
|
|
3
|
+
*
|
|
4
|
+
* Validates that a directory is a valid agent repository by checking:
|
|
5
|
+
* - agent.yaml exists and is valid YAML conforming to AgentConfigSchema
|
|
6
|
+
* - docker.network is not "none" (agents need network access for Anthropic API)
|
|
7
|
+
* - herdctl.json is valid if present
|
|
8
|
+
* - Optional files like CLAUDE.md and README.md
|
|
9
|
+
*/
|
|
10
|
+
import { type AgentConfig } from "../config/schema.js";
|
|
11
|
+
import { type AgentRepoMetadata } from "./agent-repo-metadata.js";
|
|
12
|
+
/**
|
|
13
|
+
* Validation message representing an error or warning
|
|
14
|
+
*/
|
|
15
|
+
export interface ValidationMessage {
|
|
16
|
+
/** Machine-readable code like 'MISSING_AGENT_YAML', 'INVALID_AGENT_YAML' */
|
|
17
|
+
code: string;
|
|
18
|
+
/** Human-readable description of the issue */
|
|
19
|
+
message: string;
|
|
20
|
+
/** File path relative to repository root (if applicable) */
|
|
21
|
+
path?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Result of repository validation
|
|
25
|
+
*/
|
|
26
|
+
export interface ValidationResult {
|
|
27
|
+
/** Whether the repository is valid for installation */
|
|
28
|
+
valid: boolean;
|
|
29
|
+
/** Agent name from agent.yaml (if valid) */
|
|
30
|
+
agentName: string | null;
|
|
31
|
+
/** Parsed agent configuration (if valid) */
|
|
32
|
+
agentConfig: AgentConfig | null;
|
|
33
|
+
/** Parsed repository metadata from herdctl.json (if present and valid) */
|
|
34
|
+
repoMetadata: AgentRepoMetadata | null;
|
|
35
|
+
/** Errors that prevent installation */
|
|
36
|
+
errors: ValidationMessage[];
|
|
37
|
+
/** Warnings the user should know about */
|
|
38
|
+
warnings: ValidationMessage[];
|
|
39
|
+
}
|
|
40
|
+
/** Error: agent.yaml not found */
|
|
41
|
+
export declare const MISSING_AGENT_YAML = "MISSING_AGENT_YAML";
|
|
42
|
+
/** Error: agent.yaml is not valid YAML */
|
|
43
|
+
export declare const YAML_PARSE_ERROR = "YAML_PARSE_ERROR";
|
|
44
|
+
/** Error: agent.yaml fails schema validation */
|
|
45
|
+
export declare const INVALID_AGENT_YAML = "INVALID_AGENT_YAML";
|
|
46
|
+
/** Error: docker.network is set to "none" */
|
|
47
|
+
export declare const DOCKER_NETWORK_NONE = "DOCKER_NETWORK_NONE";
|
|
48
|
+
/** Error: herdctl.json is not valid JSON */
|
|
49
|
+
export declare const JSON_PARSE_ERROR = "JSON_PARSE_ERROR";
|
|
50
|
+
/** Error: herdctl.json fails schema validation */
|
|
51
|
+
export declare const INVALID_HERDCTL_JSON = "INVALID_HERDCTL_JSON";
|
|
52
|
+
/** Warning: no herdctl.json (optional but recommended) */
|
|
53
|
+
export declare const MISSING_HERDCTL_JSON = "MISSING_HERDCTL_JSON";
|
|
54
|
+
/** Warning: name in agent.yaml differs from name in herdctl.json */
|
|
55
|
+
export declare const NAME_MISMATCH = "NAME_MISMATCH";
|
|
56
|
+
/** Warning: no CLAUDE.md file (optional but recommended) */
|
|
57
|
+
export declare const MISSING_CLAUDE_MD = "MISSING_CLAUDE_MD";
|
|
58
|
+
/** Warning: no README.md (optional but recommended) */
|
|
59
|
+
export declare const MISSING_README = "MISSING_README";
|
|
60
|
+
/**
|
|
61
|
+
* Validate a directory as an agent repository
|
|
62
|
+
*
|
|
63
|
+
* Checks that the directory contains valid agent repository files:
|
|
64
|
+
* - agent.yaml (required) - must be valid YAML conforming to AgentConfigSchema
|
|
65
|
+
* - herdctl.json (optional) - if present, must be valid JSON conforming to AgentRepoMetadataSchema
|
|
66
|
+
* - CLAUDE.md (optional) - recommended for agent identity
|
|
67
|
+
* - README.md (optional) - recommended for documentation
|
|
68
|
+
*
|
|
69
|
+
* Also performs safety checks:
|
|
70
|
+
* - docker.network cannot be "none" (agents need network for Anthropic API)
|
|
71
|
+
*
|
|
72
|
+
* @param dirPath - Absolute path to the directory to validate
|
|
73
|
+
* @returns Validation result with errors, warnings, and parsed configurations
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const result = await validateRepository("/tmp/my-agent");
|
|
78
|
+
* if (result.valid) {
|
|
79
|
+
* console.log(`Agent ${result.agentName} is valid`);
|
|
80
|
+
* } else {
|
|
81
|
+
* console.error("Validation errors:", result.errors);
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function validateRepository(dirPath: string): Promise<ValidationResult>;
|
|
86
|
+
//# sourceMappingURL=repository-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-validator.d.ts","sourceRoot":"","sources":["../../src/distribution/repository-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EAAE,KAAK,iBAAiB,EAA2B,MAAM,0BAA0B,CAAC;AAQ3F;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,KAAK,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,4CAA4C;IAC5C,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,0EAA0E;IAC1E,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACvC,uCAAuC;IACvC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,0CAA0C;IAC1C,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAMD,kCAAkC;AAClC,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,0CAA0C;AAC1C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,gDAAgD;AAChD,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,6CAA6C;AAC7C,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AACzD,4CAA4C;AAC5C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,kDAAkD;AAClD,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAE3D,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,oEAAoE;AACpE,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAC7C,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,uDAAuD;AACvD,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAwE/C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2LnF"}
|