@agentrules/core 0.0.3 → 0.0.4
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/index.d.ts +69 -29
- package/dist/index.js +97 -29
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
//#region src/types/
|
|
3
|
+
//#region src/types/constants.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Shared constants for agentrules presets and registry.
|
|
6
|
+
*/
|
|
7
|
+
/** Filename for preset configuration */
|
|
8
|
+
/**
|
|
9
|
+
* Shared constants for agentrules presets and registry.
|
|
10
|
+
*/
|
|
11
|
+
/** Filename for preset configuration */
|
|
12
|
+
declare const PRESET_CONFIG_FILENAME = "agentrules.json";
|
|
13
|
+
/** JSON Schema URL for preset configuration */
|
|
14
|
+
declare const PRESET_SCHEMA_URL = "https://agentrules.directory/schema/agentrules.json";
|
|
4
15
|
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/types/platform.d.ts
|
|
5
18
|
/**
|
|
6
19
|
* Single source of truth for platform IDs.
|
|
7
20
|
* Add new platforms here - types and config will follow.
|
|
@@ -29,6 +42,7 @@ declare const PLATFORMS: Record<PlatformId, PlatformConfig>;
|
|
|
29
42
|
declare const CONFIG_DIR_NAME = "config";
|
|
30
43
|
declare function isSupportedPlatform(value: string): value is PlatformId;
|
|
31
44
|
declare function normalizePlatformInput(value: string): PlatformId;
|
|
45
|
+
|
|
32
46
|
//#endregion
|
|
33
47
|
//#region src/types/definitions.d.ts
|
|
34
48
|
type AuthorInfo = {
|
|
@@ -37,7 +51,8 @@ type AuthorInfo = {
|
|
|
37
51
|
url?: string;
|
|
38
52
|
};
|
|
39
53
|
type PlatformPresetConfig = {
|
|
40
|
-
|
|
54
|
+
/** Path to platform config files. Defaults to platform's projectDir (e.g., ".opencode") */
|
|
55
|
+
path?: string;
|
|
41
56
|
features?: string[];
|
|
42
57
|
installMessage?: string;
|
|
43
58
|
};
|
|
@@ -45,11 +60,11 @@ type PresetConfig = {
|
|
|
45
60
|
$schema?: string;
|
|
46
61
|
name: string;
|
|
47
62
|
title: string;
|
|
48
|
-
version
|
|
63
|
+
version?: string;
|
|
49
64
|
description: string;
|
|
50
65
|
tags?: string[];
|
|
51
66
|
author?: AuthorInfo;
|
|
52
|
-
license
|
|
67
|
+
license: string;
|
|
53
68
|
platforms: Partial<Record<PlatformId, PlatformPresetConfig>>;
|
|
54
69
|
};
|
|
55
70
|
type BundledFile = {
|
|
@@ -67,10 +82,11 @@ type RegistryBundle = {
|
|
|
67
82
|
description: string;
|
|
68
83
|
tags: string[];
|
|
69
84
|
author?: AuthorInfo;
|
|
70
|
-
license
|
|
85
|
+
license: string;
|
|
86
|
+
licenseContent?: string;
|
|
87
|
+
readmeContent?: string;
|
|
71
88
|
features?: string[];
|
|
72
89
|
installMessage?: string;
|
|
73
|
-
readme?: string;
|
|
74
90
|
files: BundledFile[];
|
|
75
91
|
};
|
|
76
92
|
type RegistryEntry = {
|
|
@@ -82,15 +98,17 @@ type RegistryEntry = {
|
|
|
82
98
|
description: string;
|
|
83
99
|
tags: string[];
|
|
84
100
|
author?: AuthorInfo;
|
|
85
|
-
license
|
|
101
|
+
license: string;
|
|
86
102
|
features?: string[];
|
|
87
103
|
installMessage?: string;
|
|
88
104
|
bundlePath: string;
|
|
89
105
|
fileCount: number;
|
|
90
106
|
/** Total size of all files in bytes */
|
|
91
107
|
totalSize: number;
|
|
92
|
-
/** Whether the preset has a README */
|
|
93
|
-
|
|
108
|
+
/** Whether the preset has a README.md */
|
|
109
|
+
hasReadmeContent?: boolean;
|
|
110
|
+
/** Whether the preset has a LICENSE.md */
|
|
111
|
+
hasLicenseContent?: boolean;
|
|
94
112
|
};
|
|
95
113
|
type RegistryData = {
|
|
96
114
|
$schema: string;
|
|
@@ -105,12 +123,15 @@ type RegistryFileInput = {
|
|
|
105
123
|
type RegistryPlatformInput = {
|
|
106
124
|
platform: PlatformId;
|
|
107
125
|
files: RegistryFileInput[];
|
|
126
|
+
/** Install message from INSTALL.txt file */
|
|
127
|
+
installMessage?: string;
|
|
108
128
|
};
|
|
109
129
|
type RegistryPresetInput = {
|
|
110
130
|
slug: string;
|
|
111
131
|
config: PresetConfig;
|
|
112
132
|
platforms: RegistryPlatformInput[];
|
|
113
|
-
|
|
133
|
+
readmeContent?: string;
|
|
134
|
+
licenseContent?: string;
|
|
114
135
|
}; //#endregion
|
|
115
136
|
//#region src/types/schema.d.ts
|
|
116
137
|
declare const platformIdSchema: z.ZodEnum<{
|
|
@@ -124,16 +145,29 @@ declare const authorSchema: z.ZodObject<{
|
|
|
124
145
|
email: z.ZodOptional<z.ZodEmail>;
|
|
125
146
|
url: z.ZodOptional<z.ZodURL>;
|
|
126
147
|
}, z.core.$strict>;
|
|
148
|
+
declare const titleSchema: z.ZodString;
|
|
149
|
+
declare const descriptionSchema: z.ZodString;
|
|
150
|
+
/** Validate a title string and return error message if invalid, undefined if valid */
|
|
151
|
+
declare function validateTitle(value: string): string | undefined;
|
|
152
|
+
/** Validate a description string and return error message if invalid, undefined if valid */
|
|
153
|
+
declare function validateDescription(value: string): string | undefined;
|
|
154
|
+
declare const slugSchema: z.ZodString;
|
|
155
|
+
/** Validate a slug string and return error message if invalid, undefined if valid */
|
|
156
|
+
declare function validateSlug(value: string): string | undefined;
|
|
157
|
+
declare const COMMON_LICENSES: readonly ["MIT", "Apache-2.0", "GPL-3.0-only", "BSD-3-Clause", "ISC", "Unlicense"];
|
|
158
|
+
type CommonLicense = (typeof COMMON_LICENSES)[number];
|
|
159
|
+
declare const licenseSchema: z.ZodString;
|
|
160
|
+
/** Validate a license string and return error message if invalid, undefined if valid */
|
|
161
|
+
declare function validateLicense(value: string): string | undefined;
|
|
127
162
|
declare const platformPresetConfigSchema: z.ZodObject<{
|
|
128
|
-
path: z.ZodString
|
|
163
|
+
path: z.ZodOptional<z.ZodString>;
|
|
129
164
|
features: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
130
|
-
installMessage: z.ZodOptional<z.ZodString>;
|
|
131
165
|
}, z.core.$strict>;
|
|
132
166
|
declare const presetConfigSchema: z.ZodObject<{
|
|
133
167
|
$schema: z.ZodOptional<z.ZodString>;
|
|
134
168
|
name: z.ZodString;
|
|
135
169
|
title: z.ZodString;
|
|
136
|
-
version: z.ZodString
|
|
170
|
+
version: z.ZodOptional<z.ZodString>;
|
|
137
171
|
description: z.ZodString;
|
|
138
172
|
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
139
173
|
author: z.ZodOptional<z.ZodObject<{
|
|
@@ -141,12 +175,11 @@ declare const presetConfigSchema: z.ZodObject<{
|
|
|
141
175
|
email: z.ZodOptional<z.ZodEmail>;
|
|
142
176
|
url: z.ZodOptional<z.ZodURL>;
|
|
143
177
|
}, z.core.$strict>>;
|
|
144
|
-
license: z.
|
|
178
|
+
license: z.ZodString;
|
|
145
179
|
platforms: z.ZodObject<{
|
|
146
180
|
[x: string]: z.ZodOptional<z.ZodObject<{
|
|
147
|
-
path: z.ZodString
|
|
181
|
+
path: z.ZodOptional<z.ZodString>;
|
|
148
182
|
features: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
149
|
-
installMessage: z.ZodOptional<z.ZodString>;
|
|
150
183
|
}, z.core.$strict>>;
|
|
151
184
|
}, z.core.$strip>;
|
|
152
185
|
}, z.core.$strict>;
|
|
@@ -173,7 +206,9 @@ declare const registryBundleSchema: z.ZodObject<{
|
|
|
173
206
|
email: z.ZodOptional<z.ZodEmail>;
|
|
174
207
|
url: z.ZodOptional<z.ZodURL>;
|
|
175
208
|
}, z.core.$strict>>;
|
|
176
|
-
license: z.
|
|
209
|
+
license: z.ZodString;
|
|
210
|
+
licenseContent: z.ZodOptional<z.ZodString>;
|
|
211
|
+
readmeContent: z.ZodOptional<z.ZodString>;
|
|
177
212
|
features: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
178
213
|
installMessage: z.ZodOptional<z.ZodString>;
|
|
179
214
|
files: z.ZodArray<z.ZodObject<{
|
|
@@ -185,17 +220,16 @@ declare const registryBundleSchema: z.ZodObject<{
|
|
|
185
220
|
}, z.core.$strip>;
|
|
186
221
|
declare const registryEntrySchema: z.ZodObject<{
|
|
187
222
|
features: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
188
|
-
installMessage: z.ZodOptional<z.ZodString>;
|
|
189
223
|
title: z.ZodString;
|
|
190
|
-
version: z.ZodString;
|
|
191
224
|
description: z.ZodString;
|
|
225
|
+
license: z.ZodString;
|
|
226
|
+
version: z.ZodString;
|
|
192
227
|
tags: z.ZodArray<z.ZodString>;
|
|
193
228
|
author: z.ZodOptional<z.ZodObject<{
|
|
194
229
|
name: z.ZodString;
|
|
195
230
|
email: z.ZodOptional<z.ZodEmail>;
|
|
196
231
|
url: z.ZodOptional<z.ZodURL>;
|
|
197
232
|
}, z.core.$strict>>;
|
|
198
|
-
license: z.ZodOptional<z.ZodString>;
|
|
199
233
|
platform: z.ZodEnum<{
|
|
200
234
|
opencode: "opencode";
|
|
201
235
|
codex: "codex";
|
|
@@ -207,20 +241,21 @@ declare const registryEntrySchema: z.ZodObject<{
|
|
|
207
241
|
bundlePath: z.ZodString;
|
|
208
242
|
fileCount: z.ZodNumber;
|
|
209
243
|
totalSize: z.ZodNumber;
|
|
244
|
+
hasReadmeContent: z.ZodOptional<z.ZodBoolean>;
|
|
245
|
+
hasLicenseContent: z.ZodOptional<z.ZodBoolean>;
|
|
210
246
|
}, z.core.$strip>;
|
|
211
247
|
declare const registryIndexSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
212
248
|
features: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
213
|
-
installMessage: z.ZodOptional<z.ZodString>;
|
|
214
249
|
title: z.ZodString;
|
|
215
|
-
version: z.ZodString;
|
|
216
250
|
description: z.ZodString;
|
|
251
|
+
license: z.ZodString;
|
|
252
|
+
version: z.ZodString;
|
|
217
253
|
tags: z.ZodArray<z.ZodString>;
|
|
218
254
|
author: z.ZodOptional<z.ZodObject<{
|
|
219
255
|
name: z.ZodString;
|
|
220
256
|
email: z.ZodOptional<z.ZodEmail>;
|
|
221
257
|
url: z.ZodOptional<z.ZodURL>;
|
|
222
258
|
}, z.core.$strict>>;
|
|
223
|
-
license: z.ZodOptional<z.ZodString>;
|
|
224
259
|
platform: z.ZodEnum<{
|
|
225
260
|
opencode: "opencode";
|
|
226
261
|
codex: "codex";
|
|
@@ -232,6 +267,8 @@ declare const registryIndexSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
|
232
267
|
bundlePath: z.ZodString;
|
|
233
268
|
fileCount: z.ZodNumber;
|
|
234
269
|
totalSize: z.ZodNumber;
|
|
270
|
+
hasReadmeContent: z.ZodOptional<z.ZodBoolean>;
|
|
271
|
+
hasLicenseContent: z.ZodOptional<z.ZodBoolean>;
|
|
235
272
|
}, z.core.$strip>>;
|
|
236
273
|
|
|
237
274
|
//#endregion
|
|
@@ -239,6 +276,8 @@ declare const registryIndexSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
|
239
276
|
type BuildRegistryDataOptions = {
|
|
240
277
|
presets: RegistryPresetInput[];
|
|
241
278
|
bundleBase?: string;
|
|
279
|
+
/** Override the auto-generated version. If not provided, uses current UTC date. */
|
|
280
|
+
version?: string;
|
|
242
281
|
};
|
|
243
282
|
type BuildRegistryDataResult = {
|
|
244
283
|
entries: RegistryEntry[];
|
|
@@ -249,6 +288,11 @@ declare function buildRegistryData(options: BuildRegistryDataOptions): BuildRegi
|
|
|
249
288
|
|
|
250
289
|
//#endregion
|
|
251
290
|
//#region src/builder/utils.d.ts
|
|
291
|
+
/**
|
|
292
|
+
* Generates a date-based version string in format YYYY.MM.DD
|
|
293
|
+
* Uses UTC to ensure consistent versioning across timezones
|
|
294
|
+
*/
|
|
295
|
+
declare function generateDateVersion(date?: Date): string;
|
|
252
296
|
declare function normalizeBundlePublicBase(value: string): string;
|
|
253
297
|
declare function isAbsoluteUrl(value: string): boolean;
|
|
254
298
|
declare function cleanInstallMessage(value: unknown): string | undefined;
|
|
@@ -265,12 +309,8 @@ declare function toUtf8String(payload: ArrayBuffer | ArrayBufferView): string;
|
|
|
265
309
|
|
|
266
310
|
//#endregion
|
|
267
311
|
//#region src/client/registry.d.ts
|
|
268
|
-
type FetchRegistryBundleResult = {
|
|
269
|
-
bundle: RegistryBundle;
|
|
270
|
-
etag: string | null;
|
|
271
|
-
};
|
|
272
312
|
declare function fetchRegistryIndex(baseUrl: string): Promise<RegistryIndex>;
|
|
273
|
-
declare function fetchRegistryBundle(baseUrl: string, bundlePath: string): Promise<
|
|
313
|
+
declare function fetchRegistryBundle(baseUrl: string, bundlePath: string): Promise<RegistryBundle>;
|
|
274
314
|
declare function resolveRegistryEntry(index: RegistryIndex, input: string, explicitPlatform?: PlatformId): RegistryEntry;
|
|
275
315
|
|
|
276
316
|
//#endregion
|
|
@@ -295,4 +335,4 @@ declare function normalizePathFragment(value?: string): string | undefined;
|
|
|
295
335
|
declare function maybeStripPrefix(pathInput: string, prefix?: string): string;
|
|
296
336
|
|
|
297
337
|
//#endregion
|
|
298
|
-
export { AuthorInfo, BuildRegistryDataOptions, BuildRegistryDataResult, BundledFile, CONFIG_DIR_NAME,
|
|
338
|
+
export { AuthorInfo, BuildRegistryDataOptions, BuildRegistryDataResult, BundledFile, COMMON_LICENSES, CONFIG_DIR_NAME, CommonLicense, DiffPreviewOptions, PLATFORMS, PLATFORM_IDS, PRESET_CONFIG_FILENAME, PRESET_SCHEMA_URL, PlatformId, PlatformPresetConfig, PresetConfig, RegistryBundle, RegistryData, RegistryEntry, RegistryFileInput, RegistryIndex, RegistryIndexItem, RegistryPlatformInput, RegistryPresetInput, authorSchema, buildRegistryData, bundledFileSchema, cleanInstallMessage, collectBundledFiles, createDiffPreview, decodeBundledFile, decodeUtf8, descriptionSchema, encodeItemName, encodeUtf8, fetchRegistryBundle, fetchRegistryIndex, generateDateVersion, isAbsoluteUrl, isLikelyText, isSupportedPlatform, licenseSchema, maybeStripPrefix, normalizeBundlePath, normalizeBundlePublicBase, normalizePathFragment, normalizePlatformInput, platformIdSchema, platformPresetConfigSchema, presetConfigSchema, registryBundleSchema, registryEntrySchema, registryIndexSchema, resolveRegistryEntry, slugSchema, titleSchema, toPosixPath, toUint8Array, toUtf8String, validateDescription, validateLicense, validatePresetConfig, validateSlug, validateTitle, verifyBundledFileChecksum };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,16 @@ import { createHash } from "crypto";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { createTwoFilesPatch } from "diff";
|
|
4
4
|
|
|
5
|
+
//#region src/types/constants.ts
|
|
6
|
+
/**
|
|
7
|
+
* Shared constants for agentrules presets and registry.
|
|
8
|
+
*/
|
|
9
|
+
/** Filename for preset configuration */
|
|
10
|
+
const PRESET_CONFIG_FILENAME = "agentrules.json";
|
|
11
|
+
/** JSON Schema URL for preset configuration */
|
|
12
|
+
const PRESET_SCHEMA_URL = "https://agentrules.directory/schema/agentrules.json";
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
5
15
|
//#region src/types/platform.ts
|
|
6
16
|
/**
|
|
7
17
|
* Single source of truth for platform IDs.
|
|
@@ -53,7 +63,7 @@ function normalizePlatformInput(value) {
|
|
|
53
63
|
|
|
54
64
|
//#endregion
|
|
55
65
|
//#region src/types/schema.ts
|
|
56
|
-
const
|
|
66
|
+
const DATE_VERSION_REGEX = /^\d{4}\.(0[1-9]|1[0-2])\.(0[1-9]|[12]\d|3[01])(-\d+)?$/;
|
|
57
67
|
const platformIdSchema = z.enum(PLATFORM_IDS);
|
|
58
68
|
const authorSchema = z.object({
|
|
59
69
|
name: z.string().trim().min(1),
|
|
@@ -62,30 +72,69 @@ const authorSchema = z.object({
|
|
|
62
72
|
}).strict();
|
|
63
73
|
const titleSchema = z.string().trim().min(1).max(120);
|
|
64
74
|
const descriptionSchema = z.string().trim().min(1).max(500);
|
|
65
|
-
|
|
75
|
+
/** Validate a title string and return error message if invalid, undefined if valid */
|
|
76
|
+
function validateTitle(value) {
|
|
77
|
+
const trimmed = value.trim();
|
|
78
|
+
if (!trimmed) return "Title is required";
|
|
79
|
+
if (trimmed.length > 120) return "Title must be 120 characters or less";
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
/** Validate a description string and return error message if invalid, undefined if valid */
|
|
83
|
+
function validateDescription(value) {
|
|
84
|
+
const trimmed = value.trim();
|
|
85
|
+
if (!trimmed) return "Description is required";
|
|
86
|
+
if (trimmed.length > 500) return "Description must be 500 characters or less";
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const versionSchema = z.string().trim().regex(DATE_VERSION_REGEX, "Version must be date-based (YYYY.MM.DD or YYYY.MM.DD-N)");
|
|
66
90
|
const tagSchema = z.string().trim().min(1).max(48);
|
|
67
91
|
const tagsSchema = z.array(tagSchema).max(10);
|
|
68
92
|
const featureSchema = z.string().trim().min(1).max(160);
|
|
69
93
|
const featuresSchema = z.array(featureSchema).max(10);
|
|
70
94
|
const installMessageSchema = z.string().trim().max(4e3);
|
|
71
|
-
const
|
|
72
|
-
const
|
|
95
|
+
const contentSchema = z.string();
|
|
96
|
+
const SLUG_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
97
|
+
const SLUG_ERROR = "Must be lowercase alphanumeric with hyphens (e.g., my-preset)";
|
|
98
|
+
const slugSchema = z.string().trim().min(1).max(64).regex(SLUG_REGEX, SLUG_ERROR);
|
|
99
|
+
/** Validate a slug string and return error message if invalid, undefined if valid */
|
|
100
|
+
function validateSlug(value) {
|
|
101
|
+
const trimmed = value.trim();
|
|
102
|
+
if (!trimmed) return "Name is required";
|
|
103
|
+
if (trimmed.length > 64) return "Name must be 64 characters or less";
|
|
104
|
+
if (!SLUG_REGEX.test(trimmed)) return SLUG_ERROR;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const COMMON_LICENSES = [
|
|
108
|
+
"MIT",
|
|
109
|
+
"Apache-2.0",
|
|
110
|
+
"GPL-3.0-only",
|
|
111
|
+
"BSD-3-Clause",
|
|
112
|
+
"ISC",
|
|
113
|
+
"Unlicense"
|
|
114
|
+
];
|
|
115
|
+
const licenseSchema = z.string().trim().min(1).max(128);
|
|
116
|
+
/** Validate a license string and return error message if invalid, undefined if valid */
|
|
117
|
+
function validateLicense(value) {
|
|
118
|
+
const trimmed = value.trim();
|
|
119
|
+
if (!trimmed) return "License is required";
|
|
120
|
+
if (trimmed.length > 128) return "License must be 128 characters or less";
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
73
123
|
const pathSchema = z.string().trim().min(1);
|
|
74
124
|
const platformPresetConfigSchema = z.object({
|
|
75
|
-
path: pathSchema,
|
|
76
|
-
features: featuresSchema.optional()
|
|
77
|
-
installMessage: installMessageSchema.optional()
|
|
125
|
+
path: pathSchema.optional(),
|
|
126
|
+
features: featuresSchema.optional()
|
|
78
127
|
}).strict();
|
|
79
128
|
const platformsObjectSchema = z.object(Object.fromEntries(PLATFORM_IDS.map((id) => [id, platformPresetConfigSchema.optional()]))).refine((p) => Object.keys(p).length > 0, { message: "At least one platform must be configured" });
|
|
80
129
|
const presetConfigSchema = z.object({
|
|
81
130
|
$schema: z.string().optional(),
|
|
82
131
|
name: slugSchema,
|
|
83
132
|
title: titleSchema,
|
|
84
|
-
version: versionSchema,
|
|
133
|
+
version: versionSchema.optional(),
|
|
85
134
|
description: descriptionSchema,
|
|
86
135
|
tags: tagsSchema.optional(),
|
|
87
136
|
author: authorSchema.optional(),
|
|
88
|
-
license: licenseSchema
|
|
137
|
+
license: licenseSchema,
|
|
89
138
|
platforms: platformsObjectSchema
|
|
90
139
|
}).strict();
|
|
91
140
|
const bundledFileSchema = z.object({
|
|
@@ -102,16 +151,25 @@ const registryBundleSchema = z.object({
|
|
|
102
151
|
description: descriptionSchema,
|
|
103
152
|
tags: tagsSchema,
|
|
104
153
|
author: authorSchema.optional(),
|
|
105
|
-
license: licenseSchema
|
|
154
|
+
license: licenseSchema,
|
|
155
|
+
licenseContent: contentSchema.optional(),
|
|
156
|
+
readmeContent: contentSchema.optional(),
|
|
106
157
|
features: featuresSchema.optional(),
|
|
107
158
|
installMessage: installMessageSchema.optional(),
|
|
108
159
|
files: z.array(bundledFileSchema).min(1)
|
|
109
160
|
});
|
|
110
|
-
const registryEntrySchema = registryBundleSchema.omit({
|
|
161
|
+
const registryEntrySchema = registryBundleSchema.omit({
|
|
162
|
+
files: true,
|
|
163
|
+
readmeContent: true,
|
|
164
|
+
licenseContent: true,
|
|
165
|
+
installMessage: true
|
|
166
|
+
}).extend({
|
|
111
167
|
name: z.string().trim().min(1),
|
|
112
168
|
bundlePath: z.string().trim().min(1),
|
|
113
169
|
fileCount: z.number().int().nonnegative(),
|
|
114
|
-
totalSize: z.number().int().nonnegative()
|
|
170
|
+
totalSize: z.number().int().nonnegative(),
|
|
171
|
+
hasReadmeContent: z.boolean().optional(),
|
|
172
|
+
hasLicenseContent: z.boolean().optional()
|
|
115
173
|
});
|
|
116
174
|
const registryIndexSchema = z.record(z.string(), registryEntrySchema);
|
|
117
175
|
|
|
@@ -137,6 +195,16 @@ function toUint8Array(payload) {
|
|
|
137
195
|
|
|
138
196
|
//#endregion
|
|
139
197
|
//#region src/builder/utils.ts
|
|
198
|
+
/**
|
|
199
|
+
* Generates a date-based version string in format YYYY.MM.DD
|
|
200
|
+
* Uses UTC to ensure consistent versioning across timezones
|
|
201
|
+
*/
|
|
202
|
+
function generateDateVersion(date = new Date()) {
|
|
203
|
+
const year = date.getUTCFullYear();
|
|
204
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
205
|
+
const day = String(date.getUTCDate()).padStart(2, "0");
|
|
206
|
+
return `${year}.${month}.${day}`;
|
|
207
|
+
}
|
|
140
208
|
function normalizeBundlePublicBase(value) {
|
|
141
209
|
const trimmed = value.trim();
|
|
142
210
|
if (!trimmed) throw new Error("--bundle-base must be a non-empty string");
|
|
@@ -162,8 +230,9 @@ function validatePresetConfig(config, slug) {
|
|
|
162
230
|
const preset = config;
|
|
163
231
|
if (!preset.name || typeof preset.name !== "string") throw new Error(`Preset ${slug} is missing a name`);
|
|
164
232
|
if (!preset.title || typeof preset.title !== "string") throw new Error(`Preset ${slug} is missing a title`);
|
|
165
|
-
if (
|
|
233
|
+
if (preset.version !== void 0 && typeof preset.version !== "string") throw new Error(`Preset ${slug} has invalid version (must be string or omitted)`);
|
|
166
234
|
if (!preset.description || typeof preset.description !== "string") throw new Error(`Preset ${slug} is missing a description`);
|
|
235
|
+
if (!preset.license || typeof preset.license !== "string") throw new Error(`Preset ${slug} is missing a license (SPDX identifier required)`);
|
|
167
236
|
if (!preset.platforms || typeof preset.platforms !== "object") throw new Error(`Preset ${slug} is missing platforms map`);
|
|
168
237
|
return preset;
|
|
169
238
|
}
|
|
@@ -185,6 +254,7 @@ function collectBundledFiles(files) {
|
|
|
185
254
|
const NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
186
255
|
function buildRegistryData(options) {
|
|
187
256
|
const bundleBase = normalizeBundlePublicBase(options.bundleBase ?? "/r");
|
|
257
|
+
const buildVersion = options.version ?? generateDateVersion();
|
|
188
258
|
const entries = [];
|
|
189
259
|
const bundles = [];
|
|
190
260
|
for (const presetInput of options.presets) {
|
|
@@ -199,38 +269,40 @@ function buildRegistryData(options) {
|
|
|
199
269
|
if (platformInput.files.length === 0) throw new Error(`Preset ${presetInput.slug}/${platform} does not include any files.`);
|
|
200
270
|
const files = createBundledFilesFromInputs(platformInput.files);
|
|
201
271
|
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
|
202
|
-
const installMessage = cleanInstallMessage(
|
|
272
|
+
const installMessage = cleanInstallMessage(platformInput.installMessage);
|
|
203
273
|
const features = platformConfig.features ?? [];
|
|
204
|
-
const
|
|
274
|
+
const readmeContent = presetInput.readmeContent?.trim() || void 0;
|
|
275
|
+
const licenseContent = presetInput.licenseContent?.trim() || void 0;
|
|
205
276
|
const entry = {
|
|
206
277
|
name: encodeItemName(presetInput.slug, platform),
|
|
207
278
|
slug: presetInput.slug,
|
|
208
279
|
platform,
|
|
209
280
|
title: presetConfig.title,
|
|
210
|
-
version:
|
|
281
|
+
version: buildVersion,
|
|
211
282
|
description: presetConfig.description,
|
|
212
283
|
tags: presetConfig.tags ?? [],
|
|
213
284
|
author: presetConfig.author,
|
|
214
285
|
license: presetConfig.license,
|
|
215
286
|
features,
|
|
216
|
-
|
|
217
|
-
bundlePath: getBundlePublicPath(bundleBase, presetInput.slug, platform),
|
|
287
|
+
bundlePath: getBundlePublicPath(bundleBase, presetInput.slug, platform, buildVersion),
|
|
218
288
|
fileCount: files.length,
|
|
219
289
|
totalSize,
|
|
220
|
-
|
|
290
|
+
hasReadmeContent: Boolean(readmeContent),
|
|
291
|
+
hasLicenseContent: Boolean(licenseContent)
|
|
221
292
|
};
|
|
222
293
|
const bundle = {
|
|
223
294
|
slug: presetInput.slug,
|
|
224
295
|
platform,
|
|
225
296
|
title: presetConfig.title,
|
|
226
|
-
version:
|
|
297
|
+
version: buildVersion,
|
|
227
298
|
description: presetConfig.description,
|
|
228
299
|
tags: presetConfig.tags ?? [],
|
|
229
300
|
author: presetConfig.author,
|
|
230
301
|
license: presetConfig.license,
|
|
302
|
+
licenseContent,
|
|
303
|
+
readmeContent,
|
|
231
304
|
features,
|
|
232
305
|
installMessage,
|
|
233
|
-
readme,
|
|
234
306
|
files
|
|
235
307
|
};
|
|
236
308
|
entries.push(entry);
|
|
@@ -273,9 +345,9 @@ function encodeFilePayload(buffer, filePath) {
|
|
|
273
345
|
if (!Buffer.from(utf8, "utf8").equals(buffer)) throw new Error(`Binary files are not supported: "${filePath}". Only UTF-8 text files are allowed.`);
|
|
274
346
|
return utf8;
|
|
275
347
|
}
|
|
276
|
-
function getBundlePublicPath(base, slug, platform) {
|
|
348
|
+
function getBundlePublicPath(base, slug, platform, version) {
|
|
277
349
|
const prefix = base === "/" ? "" : base;
|
|
278
|
-
return `${prefix}/${slug}/${platform}.json`;
|
|
350
|
+
return `${prefix}/${slug}/${platform}.${version}.json`;
|
|
279
351
|
}
|
|
280
352
|
function ensureKnownPlatform(platform, slug) {
|
|
281
353
|
if (!isSupportedPlatform(platform)) throw new Error(`Unknown platform "${platform}" in ${slug}. Supported: ${PLATFORM_IDS.join(", ")}`);
|
|
@@ -334,11 +406,7 @@ async function fetchRegistryBundle(baseUrl, bundlePath) {
|
|
|
334
406
|
const response = await fetch(bundleUrl);
|
|
335
407
|
if (!response.ok) throw new Error(`Failed to download bundle (${response.status} ${response.statusText}).`);
|
|
336
408
|
try {
|
|
337
|
-
|
|
338
|
-
return {
|
|
339
|
-
bundle,
|
|
340
|
-
etag: response.headers.get("etag")
|
|
341
|
-
};
|
|
409
|
+
return await response.json();
|
|
342
410
|
} catch (error) {
|
|
343
411
|
throw new Error(`Unable to parse bundle JSON: ${error.message}`);
|
|
344
412
|
}
|
|
@@ -404,4 +472,4 @@ function maybeStripPrefix(pathInput, prefix) {
|
|
|
404
472
|
}
|
|
405
473
|
|
|
406
474
|
//#endregion
|
|
407
|
-
export { CONFIG_DIR_NAME, PLATFORMS, PLATFORM_IDS, authorSchema, buildRegistryData, bundledFileSchema, cleanInstallMessage, collectBundledFiles, createDiffPreview, decodeBundledFile, decodeUtf8, encodeItemName, encodeUtf8, fetchRegistryBundle, fetchRegistryIndex, isAbsoluteUrl, isLikelyText, isSupportedPlatform, maybeStripPrefix, normalizeBundlePath, normalizeBundlePublicBase, normalizePathFragment, normalizePlatformInput, platformIdSchema, platformPresetConfigSchema, presetConfigSchema, registryBundleSchema, registryEntrySchema, registryIndexSchema, resolveRegistryEntry, toPosixPath, toUint8Array, toUtf8String, validatePresetConfig, verifyBundledFileChecksum };
|
|
475
|
+
export { COMMON_LICENSES, CONFIG_DIR_NAME, PLATFORMS, PLATFORM_IDS, PRESET_CONFIG_FILENAME, PRESET_SCHEMA_URL, authorSchema, buildRegistryData, bundledFileSchema, cleanInstallMessage, collectBundledFiles, createDiffPreview, decodeBundledFile, decodeUtf8, descriptionSchema, encodeItemName, encodeUtf8, fetchRegistryBundle, fetchRegistryIndex, generateDateVersion, isAbsoluteUrl, isLikelyText, isSupportedPlatform, licenseSchema, maybeStripPrefix, normalizeBundlePath, normalizeBundlePublicBase, normalizePathFragment, normalizePlatformInput, platformIdSchema, platformPresetConfigSchema, presetConfigSchema, registryBundleSchema, registryEntrySchema, registryIndexSchema, resolveRegistryEntry, slugSchema, titleSchema, toPosixPath, toUint8Array, toUtf8String, validateDescription, validateLicense, validatePresetConfig, validateSlug, validateTitle, verifyBundledFileChecksum };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentrules/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"author": "Brian Cheung <bcheung.dev@gmail.com> (https://github.com/bcheung)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://docs.agentrules.directory",
|
|
@@ -51,4 +51,4 @@
|
|
|
51
51
|
"tsdown": "^0.9.0",
|
|
52
52
|
"typescript": "5.7.2"
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
}
|