@hachej/boring-agent 0.1.78 → 0.1.79

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.
@@ -0,0 +1,264 @@
1
+ import {
2
+ AgentDefinitionErrorCode,
3
+ AgentDeploymentErrorCode,
4
+ ErrorCode
5
+ } from "./chunk-YVON2BHN.js";
6
+
7
+ // src/shared/agent-definition.ts
8
+ import { z } from "zod";
9
+ var SHA256_DIGEST_RE = /^sha256:[a-f0-9]{64}$/;
10
+ function hasWellFormedUnicode(value) {
11
+ for (let index = 0; index < value.length; index += 1) {
12
+ const code = value.charCodeAt(index);
13
+ if (code >= 55296 && code <= 56319) {
14
+ if (index + 1 >= value.length) return false;
15
+ const next = value.charCodeAt(index + 1);
16
+ if (next < 56320 || next > 57343) return false;
17
+ index += 1;
18
+ } else if (code >= 56320 && code <= 57343) {
19
+ return false;
20
+ }
21
+ }
22
+ return true;
23
+ }
24
+ function isOpaqueRef(value) {
25
+ return hasWellFormedUnicode(value) && value.trim() === value && !/[\0-\x1f\x7f]/.test(value);
26
+ }
27
+ function isSafeAssetPath(value) {
28
+ const segments = value.split("/");
29
+ return hasWellFormedUnicode(value) && value.normalize("NFC") === value && !/[\0-\x1f\x7f]/.test(value) && !value.includes("\\") && !value.startsWith("/") && !/^[A-Za-z]:[\\/]/.test(value) && !value.startsWith("./") && segments.every((segment) => segment !== "" && segment !== "." && segment !== "..");
30
+ }
31
+ var OpaqueRefSchema = z.string().min(1, "must be a non-empty reference").max(256, "must be at most 256 characters").refine(isOpaqueRef, "must be a non-empty reference");
32
+ var ReferenceArraySchema = z.array(OpaqueRefSchema).superRefine((refs, ctx) => {
33
+ const seen = /* @__PURE__ */ new Set();
34
+ refs.forEach((ref, index) => {
35
+ if (seen.has(ref)) {
36
+ ctx.addIssue({
37
+ code: z.ZodIssueCode.custom,
38
+ path: [index],
39
+ message: "must not contain duplicate references"
40
+ });
41
+ }
42
+ seen.add(ref);
43
+ });
44
+ });
45
+ var SafeAssetPathSchema = z.string().min(1).refine(isSafeAssetPath, "must be a safe relative asset path");
46
+ var Sha256DigestSchema = z.string().regex(SHA256_DIGEST_RE, "must be a lowercase sha256 digest").transform((value) => value);
47
+ var AgentDefinitionSchema = z.object({
48
+ schemaVersion: z.literal(1),
49
+ definitionId: OpaqueRefSchema,
50
+ version: OpaqueRefSchema,
51
+ label: z.string().refine(hasWellFormedUnicode, "must contain well-formed Unicode").optional(),
52
+ instructionsRef: SafeAssetPathSchema,
53
+ capabilityRequirements: ReferenceArraySchema.optional(),
54
+ toolRefs: ReferenceArraySchema.optional(),
55
+ skillRefs: ReferenceArraySchema.optional(),
56
+ mcpServerRefs: ReferenceArraySchema.optional()
57
+ }).strict();
58
+ var AgentDefinitionReferenceSchema = z.object({
59
+ definitionId: OpaqueRefSchema,
60
+ version: OpaqueRefSchema,
61
+ digest: Sha256DigestSchema
62
+ }).strict();
63
+ var AgentDeploymentSchema = z.object({
64
+ deploymentId: OpaqueRefSchema,
65
+ version: OpaqueRefSchema,
66
+ agentId: OpaqueRefSchema,
67
+ definition: AgentDefinitionReferenceSchema
68
+ }).strict();
69
+ var AgentDefinitionDigestAssetSchema = z.object({
70
+ path: SafeAssetPathSchema,
71
+ digest: Sha256DigestSchema,
72
+ content: z.string().refine(hasWellFormedUnicode, "must contain well-formed Unicode")
73
+ }).strict();
74
+ function formatPath(path) {
75
+ if (path.length === 0) return "<root>";
76
+ return path.reduce(
77
+ (result, part) => typeof part === "number" ? `${result}[${part}]` : result.length === 0 ? String(part) : `${result}.${String(part)}`,
78
+ ""
79
+ );
80
+ }
81
+ function mapZodIssues(issues, invalidCode, unsupportedCode) {
82
+ return issues.flatMap((issue) => {
83
+ if (issue.code === z.ZodIssueCode.unrecognized_keys) {
84
+ const parent = formatPath(issue.path);
85
+ return [...issue.keys].sort().map((key) => ({
86
+ code: unsupportedCode,
87
+ field: parent === "<root>" ? key : `${parent}.${key}`,
88
+ message: `${key} is not supported by schema version 1`
89
+ }));
90
+ }
91
+ const field = formatPath(issue.path);
92
+ return [{
93
+ code: invalidCode,
94
+ field,
95
+ message: field === "<root>" ? issue.message : `${field} ${issue.message}`
96
+ }];
97
+ });
98
+ }
99
+ function validateAgentDefinition(raw) {
100
+ const result = AgentDefinitionSchema.safeParse(raw);
101
+ if (!result.success) {
102
+ return {
103
+ valid: false,
104
+ issues: mapZodIssues(
105
+ result.error.issues,
106
+ AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
107
+ AgentDefinitionErrorCode.enum.AGENT_DEFINITION_UNSUPPORTED_FIELD
108
+ )
109
+ };
110
+ }
111
+ return { valid: true, value: result.data };
112
+ }
113
+ function validateAgentDeployment(raw) {
114
+ const result = AgentDeploymentSchema.safeParse(raw);
115
+ if (!result.success) {
116
+ return {
117
+ valid: false,
118
+ issues: mapZodIssues(
119
+ result.error.issues,
120
+ AgentDeploymentErrorCode.enum.AGENT_DEPLOYMENT_INVALID,
121
+ AgentDeploymentErrorCode.enum.AGENT_DEPLOYMENT_UNSUPPORTED_FIELD
122
+ )
123
+ };
124
+ }
125
+ return { valid: true, value: result.data };
126
+ }
127
+ function canonicalStringify(value) {
128
+ if (value === null || typeof value !== "object") {
129
+ const encoded = JSON.stringify(value);
130
+ if (encoded === void 0) throw new TypeError("Cannot canonicalize undefined");
131
+ return encoded;
132
+ }
133
+ if (Array.isArray(value)) return `[${value.map(canonicalStringify).join(",")}]`;
134
+ const record = value;
135
+ return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalStringify(record[key])}`).join(",")}}`;
136
+ }
137
+ async function sha256(value) {
138
+ const hash = await globalThis.crypto.subtle.digest(
139
+ "SHA-256",
140
+ new TextEncoder().encode(value)
141
+ );
142
+ const hex = Array.from(
143
+ new Uint8Array(hash),
144
+ (byte) => byte.toString(16).padStart(2, "0")
145
+ ).join("");
146
+ return `sha256:${hex}`;
147
+ }
148
+ async function createAgentAssetDigest(content) {
149
+ if (!hasWellFormedUnicode(content)) {
150
+ throw new AgentDefinitionValidationError({
151
+ code: AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
152
+ field: "content",
153
+ message: "content must contain well-formed Unicode"
154
+ });
155
+ }
156
+ return sha256(content);
157
+ }
158
+ var AgentDefinitionValidationError = class extends Error {
159
+ code = ErrorCode.enum.CONFIG_INVALID;
160
+ field;
161
+ validationCode;
162
+ constructor(issue) {
163
+ super(issue.message);
164
+ this.name = "AgentDefinitionValidationError";
165
+ this.field = issue.field;
166
+ this.validationCode = issue.code;
167
+ }
168
+ };
169
+ var AgentDeploymentValidationError = class extends Error {
170
+ code = ErrorCode.enum.CONFIG_INVALID;
171
+ field;
172
+ validationCode;
173
+ constructor(issue) {
174
+ super(issue.message);
175
+ this.name = "AgentDeploymentValidationError";
176
+ this.field = issue.field;
177
+ this.validationCode = issue.code;
178
+ }
179
+ };
180
+ async function validatedDefinitionAssets(definition, assets) {
181
+ if (!Array.isArray(assets)) {
182
+ throw new AgentDefinitionValidationError({
183
+ code: AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
184
+ field: "assets",
185
+ message: "assets must be an array"
186
+ });
187
+ }
188
+ const canonicalAssets = [];
189
+ for (const [index, input] of assets.entries()) {
190
+ const result = AgentDefinitionDigestAssetSchema.safeParse(input);
191
+ if (!result.success) {
192
+ const issue = mapZodIssues(
193
+ result.error.issues,
194
+ AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
195
+ AgentDefinitionErrorCode.enum.AGENT_DEFINITION_UNSUPPORTED_FIELD
196
+ )[0];
197
+ throw new AgentDefinitionValidationError({
198
+ ...issue,
199
+ field: `assets[${index}].${issue.field}`
200
+ });
201
+ }
202
+ if (await createAgentAssetDigest(result.data.content) !== result.data.digest) {
203
+ throw new AgentDefinitionValidationError({
204
+ code: AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
205
+ field: "assets.digest",
206
+ message: `asset digest does not match UTF-8 content: ${result.data.path}`
207
+ });
208
+ }
209
+ canonicalAssets.push(result.data);
210
+ }
211
+ canonicalAssets.sort(
212
+ (left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0
213
+ );
214
+ for (let index = 1; index < canonicalAssets.length; index += 1) {
215
+ if (canonicalAssets[index - 1].path === canonicalAssets[index].path) {
216
+ throw new AgentDefinitionValidationError({
217
+ code: AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
218
+ field: "assets.path",
219
+ message: `duplicate asset path: ${canonicalAssets[index].path}`
220
+ });
221
+ }
222
+ }
223
+ if (!canonicalAssets.some((asset) => asset.path === definition.instructionsRef)) {
224
+ throw new AgentDefinitionValidationError({
225
+ code: AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
226
+ field: "instructionsRef",
227
+ message: "instructionsRef must name an included verified asset"
228
+ });
229
+ }
230
+ return canonicalAssets;
231
+ }
232
+ async function createAgentDefinitionDigest(input) {
233
+ const validated = validateAgentDefinition(input.definition);
234
+ if (!validated.valid) throw new AgentDefinitionValidationError(validated.issues[0]);
235
+ const assets = await validatedDefinitionAssets(validated.value, input.assets);
236
+ return sha256(canonicalStringify({ definition: validated.value, assets }));
237
+ }
238
+ async function createAgentDeploymentDigest(deployment) {
239
+ const validated = validateAgentDeployment(deployment);
240
+ if (!validated.valid) throw new AgentDeploymentValidationError(validated.issues[0]);
241
+ return sha256(canonicalStringify(validated.value));
242
+ }
243
+
244
+ // src/shared/validateTool.ts
245
+ function validateTool(tool) {
246
+ if (typeof tool !== "object" || tool === null) return null;
247
+ const t = tool;
248
+ if (typeof t.name !== "string" || t.name.length === 0) return null;
249
+ if (typeof t.description !== "string") return null;
250
+ if (typeof t.parameters !== "object" || t.parameters === null) return null;
251
+ if (typeof t.execute !== "function") return null;
252
+ return t;
253
+ }
254
+
255
+ export {
256
+ validateAgentDefinition,
257
+ validateAgentDeployment,
258
+ createAgentAssetDigest,
259
+ AgentDefinitionValidationError,
260
+ AgentDeploymentValidationError,
261
+ createAgentDefinitionDigest,
262
+ createAgentDeploymentDigest,
263
+ validateTool
264
+ };