orizu 0.5.26 → 0.5.28
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/README.md +19 -0
- package/dist/artifacts-git-runtime.d.ts +34 -0
- package/dist/artifacts-git-runtime.d.ts.map +1 -0
- package/dist/artifacts-git-runtime.js +312 -0
- package/dist/cloudflare-artifacts-git-remote.d.ts +5 -0
- package/dist/cloudflare-artifacts-git-remote.d.ts.map +1 -0
- package/dist/cloudflare-artifacts-git-remote.js +21 -0
- package/dist/dataset-transfer-download.d.ts +2 -0
- package/dist/dataset-transfer-download.d.ts.map +1 -0
- package/dist/dataset-transfer-download.js +66 -0
- package/dist/dataset-transfer-policy.d.ts +2 -0
- package/dist/dataset-transfer-policy.d.ts.map +1 -0
- package/dist/dataset-transfer-policy.js +8 -0
- package/dist/dataset-transfer-upload.d.ts +42 -0
- package/dist/dataset-transfer-upload.d.ts.map +1 -0
- package/dist/dataset-transfer-upload.js +110 -0
- package/dist/git-credential.d.ts.map +1 -1
- package/dist/git-credential.js +1 -1
- package/dist/git-recovery-environment.d.ts +1 -0
- package/dist/git-recovery-environment.d.ts.map +1 -1
- package/dist/git-recovery-environment.js +1 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +44 -11
- package/dist/hosted-boot.d.ts +75 -2
- package/dist/hosted-boot.d.ts.map +1 -1
- package/dist/hosted-boot.js +585 -102
- package/dist/hosted-bootstrap.d.ts +2 -0
- package/dist/hosted-bootstrap.d.ts.map +1 -1
- package/dist/hosted-bootstrap.js +12 -3
- package/dist/hosted-harness-opencode.d.ts +8 -9
- package/dist/hosted-harness-opencode.d.ts.map +1 -1
- package/dist/hosted-harness-opencode.js +126 -24
- package/dist/hosted-harness.d.ts +3 -0
- package/dist/hosted-harness.d.ts.map +1 -1
- package/dist/hosted-harness.js +4 -1
- package/dist/hosted-harvest.d.ts +30 -9
- package/dist/hosted-harvest.d.ts.map +1 -1
- package/dist/hosted-harvest.js +222 -28
- package/dist/hosted-loop-lifecycle.d.ts +15 -3
- package/dist/hosted-loop-lifecycle.d.ts.map +1 -1
- package/dist/hosted-loop-lifecycle.js +6 -4
- package/dist/hosted-loop.d.ts +47 -7
- package/dist/hosted-loop.d.ts.map +1 -1
- package/dist/hosted-loop.js +310 -64
- package/dist/hosted-question-limits.d.ts +7 -0
- package/dist/hosted-question-limits.d.ts.map +1 -0
- package/dist/hosted-question-limits.js +6 -0
- package/dist/hosted-question.d.ts +27 -0
- package/dist/hosted-question.d.ts.map +1 -0
- package/dist/hosted-question.js +118 -0
- package/dist/hosted-run-event-sink.d.ts +10 -5
- package/dist/hosted-run-event-sink.d.ts.map +1 -1
- package/dist/hosted-run-event-sink.js +12 -8
- package/dist/hosted-runtime-assets.d.ts +16 -7
- package/dist/hosted-runtime-assets.d.ts.map +1 -1
- package/dist/hosted-runtime-assets.js +40 -12
- package/dist/hosted-session-cli.d.ts.map +1 -1
- package/dist/hosted-session-cli.js +10 -19
- package/dist/http.d.ts +1 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +113 -92
- package/dist/instruction-set-gepa-launch.d.ts +1 -1
- package/dist/instruction-set-gepa-launch.d.ts.map +1 -1
- package/dist/instruction-set-gepa-launch.js +5 -3
- package/dist/instruction-set-loader.d.ts.map +1 -1
- package/dist/instruction-set-loader.js +63 -2
- package/dist/instruction-set-lock/index.d.ts +51 -0
- package/dist/instruction-set-lock/index.d.ts.map +1 -0
- package/dist/instruction-set-lock/index.js +459 -0
- package/dist/instruction-set-lock/schema.v1.d.ts +136 -0
- package/dist/instruction-set-lock/schema.v1.d.ts.map +1 -0
- package/dist/instruction-set-lock/schema.v1.js +155 -0
- package/dist/instruction-set-provenance.d.ts +26 -0
- package/dist/instruction-set-provenance.d.ts.map +1 -0
- package/dist/instruction-set-provenance.js +68 -0
- package/dist/instruction-set-sync/helpers.d.ts +22 -0
- package/dist/instruction-set-sync/helpers.d.ts.map +1 -0
- package/dist/instruction-set-sync/helpers.js +677 -0
- package/dist/instruction-set-sync/index.d.ts +60 -0
- package/dist/instruction-set-sync/index.d.ts.map +1 -0
- package/dist/instruction-set-sync/index.js +689 -0
- package/dist/instruction-set-update/index.d.ts +42 -0
- package/dist/instruction-set-update/index.d.ts.map +1 -0
- package/dist/instruction-set-update/index.js +445 -0
- package/dist/instruction-set-verify/index.d.ts +27 -0
- package/dist/instruction-set-verify/index.d.ts.map +1 -0
- package/dist/instruction-set-verify/index.js +865 -0
- package/dist/instruction-sets-cli.d.ts +1 -4
- package/dist/instruction-sets-cli.d.ts.map +1 -1
- package/dist/instruction-sets-cli.js +220 -109
- package/dist/model-config-fields.d.ts +35 -0
- package/dist/model-config-fields.d.ts.map +1 -0
- package/dist/model-config-fields.js +28 -0
- package/dist/optimizations-list-cli.d.ts.map +1 -1
- package/dist/optimizations-list-cli.js +7 -4
- package/dist/score-format.d.ts +2 -0
- package/dist/score-format.d.ts.map +1 -0
- package/dist/score-format.js +18 -0
- package/dist/workbench-repo-contract.d.ts +65 -0
- package/dist/workbench-repo-contract.d.ts.map +1 -0
- package/dist/workbench-repo-contract.js +250 -0
- package/dist/workspace-bootstrap-job.d.ts +45 -0
- package/dist/workspace-bootstrap-job.d.ts.map +1 -0
- package/dist/workspace-bootstrap-job.js +431 -0
- package/dist/workspace-bootstrap-seed.d.ts +74 -0
- package/dist/workspace-bootstrap-seed.d.ts.map +1 -0
- package/dist/workspace-bootstrap-seed.js +209 -0
- package/package.json +4 -3
- package/src/artifacts-git-runtime.ts +360 -0
- package/src/cloudflare-artifacts-git-remote.ts +24 -0
- package/src/dataset-transfer-download.ts +61 -0
- package/src/dataset-transfer-policy.ts +8 -0
- package/src/dataset-transfer-upload.ts +145 -0
- package/src/git-credential.ts +1 -2
- package/src/git-recovery-environment.ts +1 -1
- package/src/help.ts +44 -11
- package/src/hosted-boot.ts +644 -109
- package/src/hosted-bootstrap.ts +14 -3
- package/src/hosted-harness-opencode.ts +130 -28
- package/src/hosted-harness.ts +4 -1
- package/src/hosted-harvest.ts +258 -33
- package/src/hosted-loop-lifecycle.ts +19 -5
- package/src/hosted-loop.ts +340 -68
- package/src/hosted-question-limits.ts +6 -0
- package/src/hosted-question.ts +145 -0
- package/src/hosted-run-event-sink.ts +24 -12
- package/src/hosted-runtime-assets.ts +51 -11
- package/src/hosted-session-cli.ts +10 -24
- package/src/http.ts +10 -4
- package/src/index.ts +108 -134
- package/src/instruction-set-gepa-launch.ts +4 -4
- package/src/instruction-set-loader.ts +53 -2
- package/src/instruction-set-lock/index.ts +561 -0
- package/src/instruction-set-lock/schema.v1.json +141 -0
- package/src/instruction-set-lock/schema.v1.ts +155 -0
- package/src/instruction-set-provenance.ts +89 -0
- package/src/instruction-set-sync/helpers.ts +707 -0
- package/src/instruction-set-sync/index.ts +791 -0
- package/src/instruction-set-update/index.ts +488 -0
- package/src/instruction-set-verify/index.ts +1067 -0
- package/src/instruction-sets-cli.ts +226 -114
- package/src/model-config-fields.ts +31 -0
- package/src/optimizations-list-cli.ts +7 -4
- package/src/score-format.ts +16 -0
- package/src/workbench-repo-contract.ts +314 -0
- package/src/workspace-bootstrap-job.ts +611 -0
- package/src/workspace-bootstrap-seed.ts +350 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +46 -2
- package/vendor/skills/orizu/SKILL.md +4 -2
- package/vendor/skills/orizu/flows/promote.md +4 -0
- package/vendor/skills/orizu/references/assess-and-plan.md +1 -1
- package/vendor/skills/orizu/references/authority-map.md +1 -1
- package/vendor/skills/orizu/references/cli-reference.md +151 -35
- package/vendor/skills/orizu/references/instructions-after-prompts.md +3 -3
- package/vendor/skills/orizu/references/migrate-existing-gepa-setup.md +5 -6
- package/vendor/skills/orizu/references/migrate-hand-rolled-instruction-layout.md +252 -0
- package/vendor/skills/orizu/references/optimization-reports.md +5 -4
- package/vendor/skills/orizu/references/optimization-with-gepa.md +1 -1
- package/vendor/skills/orizu/references/orizu-in-your-codebase.md +195 -0
- package/vendor/skills/orizu/references/primer.md +4 -2
- package/vendor/skills/orizu/references/prompt-control-plane.md +33 -29
- package/vendor/skills/orizu/references/vocabulary.md +1 -1
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { instructionSetLockSchemaV1 } from './schema.v1.js';
|
|
2
|
+
export class LockParseError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
path;
|
|
5
|
+
constructor(code, path) {
|
|
6
|
+
super(code);
|
|
7
|
+
this.name = 'LockParseError';
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.path = path;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class SpecifierParseError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(code) {
|
|
15
|
+
super(code);
|
|
16
|
+
this.name = 'SpecifierParseError';
|
|
17
|
+
this.code = code;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const lockSchema = instructionSetLockSchemaV1;
|
|
21
|
+
const rootSchema = lockSchema;
|
|
22
|
+
export const INSTRUCTION_SET_SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
23
|
+
export const INSTRUCTION_SET_PROFILE_SLUG = /^[a-z0-9][a-z0-9._-]*__[a-z0-9][a-z0-9._-]*$/u;
|
|
24
|
+
export const INSTRUCTION_SET_COMPONENT_KEY = /^(?!\.)[A-Za-z0-9._-]+$/u;
|
|
25
|
+
const WINDOWS_RESERVED_COMPONENT_KEY = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\.|$)/iu;
|
|
26
|
+
export const INSTRUCTION_SET_HELPER_PATH = /^helpers\/(?!\.{1,2}(?:\/|$))(?!.*\/\.{1,2}(?:\/|$))[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/u;
|
|
27
|
+
export const MAX_VERSION_NUMBER = 2_147_483_647;
|
|
28
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
29
|
+
export function windowsPathIdentity(value) {
|
|
30
|
+
return value.toLowerCase().replace(/[. ]+$/u, '');
|
|
31
|
+
}
|
|
32
|
+
function escapeJsonPointer(segment) {
|
|
33
|
+
return segment.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
34
|
+
}
|
|
35
|
+
function childPath(path, segment) {
|
|
36
|
+
return `${path}/${escapeJsonPointer(segment)}`;
|
|
37
|
+
}
|
|
38
|
+
function schemaAtReference(reference) {
|
|
39
|
+
if (!reference.startsWith('#/'))
|
|
40
|
+
return {};
|
|
41
|
+
let current = lockSchema;
|
|
42
|
+
for (const encodedSegment of reference.slice(2).split('/')) {
|
|
43
|
+
const segment = encodedSegment.replaceAll('~1', '/').replaceAll('~0', '~');
|
|
44
|
+
if (!current || typeof current !== 'object' || Array.isArray(current))
|
|
45
|
+
return {};
|
|
46
|
+
current = current[segment];
|
|
47
|
+
}
|
|
48
|
+
return current && typeof current === 'object' && !Array.isArray(current)
|
|
49
|
+
? current
|
|
50
|
+
: {};
|
|
51
|
+
}
|
|
52
|
+
function hasJsonType(value, expected) {
|
|
53
|
+
if (expected === 'null')
|
|
54
|
+
return value === null;
|
|
55
|
+
if (expected === 'array')
|
|
56
|
+
return Array.isArray(value);
|
|
57
|
+
if (expected === 'object')
|
|
58
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
59
|
+
if (expected === 'integer')
|
|
60
|
+
return typeof value === 'number' && Number.isSafeInteger(value);
|
|
61
|
+
return typeof value === expected;
|
|
62
|
+
}
|
|
63
|
+
function isValidDateTime(value) {
|
|
64
|
+
const parsed = new Date(value);
|
|
65
|
+
if (Number.isNaN(parsed.valueOf()))
|
|
66
|
+
return false;
|
|
67
|
+
const canonicalUtc = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z$/u;
|
|
68
|
+
return !canonicalUtc.test(value) || parsed.toISOString() === value;
|
|
69
|
+
}
|
|
70
|
+
function firstSchemaViolation(value, schema, path) {
|
|
71
|
+
if (schema.$ref)
|
|
72
|
+
return firstSchemaViolation(value, schemaAtReference(schema.$ref), path);
|
|
73
|
+
if (Object.hasOwn(schema, 'const') && value !== schema.const)
|
|
74
|
+
return path || '/';
|
|
75
|
+
if (schema.type) {
|
|
76
|
+
const expectedTypes = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
77
|
+
if (!expectedTypes.some(expected => hasJsonType(value, expected)))
|
|
78
|
+
return path || '/';
|
|
79
|
+
}
|
|
80
|
+
if (typeof value === 'string') {
|
|
81
|
+
if (schema.minLength !== undefined && value.length < schema.minLength)
|
|
82
|
+
return path || '/';
|
|
83
|
+
if (schema.pattern && !new RegExp(schema.pattern, 'u').test(value))
|
|
84
|
+
return path || '/';
|
|
85
|
+
if (schema.format === 'uuid' && !UUID.test(value))
|
|
86
|
+
return path || '/';
|
|
87
|
+
if (schema.format === 'date-time' && !isValidDateTime(value))
|
|
88
|
+
return path || '/';
|
|
89
|
+
}
|
|
90
|
+
if (typeof value === 'number') {
|
|
91
|
+
if (schema.minimum !== undefined && value < schema.minimum)
|
|
92
|
+
return path || '/';
|
|
93
|
+
if (schema.maximum !== undefined && value > schema.maximum)
|
|
94
|
+
return path || '/';
|
|
95
|
+
}
|
|
96
|
+
if (Array.isArray(value)) {
|
|
97
|
+
if (schema.uniqueItems) {
|
|
98
|
+
const seen = new Set(value.map(item => JSON.stringify(item)));
|
|
99
|
+
if (seen.size !== value.length)
|
|
100
|
+
return path || '/';
|
|
101
|
+
}
|
|
102
|
+
if (schema.items) {
|
|
103
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
104
|
+
const violation = firstSchemaViolation(value[index], schema.items, childPath(path, String(index)));
|
|
105
|
+
if (violation)
|
|
106
|
+
return violation;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
if (value === null || typeof value !== 'object')
|
|
112
|
+
return null;
|
|
113
|
+
const object = value;
|
|
114
|
+
const keys = Object.keys(object);
|
|
115
|
+
if (schema.minProperties !== undefined && keys.length < schema.minProperties)
|
|
116
|
+
return path || '/';
|
|
117
|
+
for (const required of schema.required ?? []) {
|
|
118
|
+
if (!Object.hasOwn(object, required))
|
|
119
|
+
return childPath(path, required);
|
|
120
|
+
}
|
|
121
|
+
for (const key of keys) {
|
|
122
|
+
const keyPath = childPath(path, key);
|
|
123
|
+
if (schema.propertyNames) {
|
|
124
|
+
const violation = firstSchemaViolation(key, schema.propertyNames, keyPath);
|
|
125
|
+
if (violation)
|
|
126
|
+
return violation;
|
|
127
|
+
}
|
|
128
|
+
const propertySchema = schema.properties && Object.hasOwn(schema.properties, key)
|
|
129
|
+
? schema.properties[key]
|
|
130
|
+
: undefined;
|
|
131
|
+
if (propertySchema) {
|
|
132
|
+
const violation = firstSchemaViolation(object[key], propertySchema, keyPath);
|
|
133
|
+
if (violation)
|
|
134
|
+
return violation;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const matchingSchemas = Object.entries(schema.patternProperties ?? {})
|
|
138
|
+
.filter(([pattern]) => new RegExp(pattern, 'u').test(key))
|
|
139
|
+
.map(([, matchingSchema]) => matchingSchema);
|
|
140
|
+
if (matchingSchemas.length > 0) {
|
|
141
|
+
for (const matchingSchema of matchingSchemas) {
|
|
142
|
+
const violation = firstSchemaViolation(object[key], matchingSchema, keyPath);
|
|
143
|
+
if (violation)
|
|
144
|
+
return violation;
|
|
145
|
+
}
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (schema.additionalProperties === false)
|
|
149
|
+
return keyPath;
|
|
150
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
|
|
151
|
+
const violation = firstSchemaViolation(object[key], schema.additionalProperties, keyPath);
|
|
152
|
+
if (violation)
|
|
153
|
+
return violation;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
function objectRecord(value) {
|
|
159
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
160
|
+
? value
|
|
161
|
+
: null;
|
|
162
|
+
}
|
|
163
|
+
function isUnsafeComponentKey(key) {
|
|
164
|
+
return !INSTRUCTION_SET_COMPONENT_KEY.test(key);
|
|
165
|
+
}
|
|
166
|
+
export function validateInstructionSetComponentKeys(componentKeys, pathPrefix = '/components', rejectWindowsReserved = false) {
|
|
167
|
+
const componentKeysByCaseFold = new Map();
|
|
168
|
+
for (const componentKey of componentKeys) {
|
|
169
|
+
const caseFoldedKey = componentKey.toLowerCase();
|
|
170
|
+
const collidingKey = componentKeysByCaseFold.get(caseFoldedKey);
|
|
171
|
+
if (collidingKey !== undefined) {
|
|
172
|
+
throw new LockParseError(`instruction_set_lock_component_key_collision:${collidingKey},${componentKey}`);
|
|
173
|
+
}
|
|
174
|
+
componentKeysByCaseFold.set(caseFoldedKey, componentKey);
|
|
175
|
+
const path = childPath(pathPrefix, componentKey);
|
|
176
|
+
if (rejectWindowsReserved && WINDOWS_RESERVED_COMPONENT_KEY.test(componentKey)) {
|
|
177
|
+
throw new LockParseError(`lock_component_key_reserved:${path}`, path);
|
|
178
|
+
}
|
|
179
|
+
if (isUnsafeComponentKey(componentKey)) {
|
|
180
|
+
throw new LockParseError(`lock_component_key_unsafe:${path}`, path);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function validateComponentKeys(value) {
|
|
185
|
+
const instructionSets = objectRecord(objectRecord(value)?.instructionSets);
|
|
186
|
+
if (!instructionSets)
|
|
187
|
+
return;
|
|
188
|
+
for (const [setSlug, instructionSetValue] of Object.entries(instructionSets)) {
|
|
189
|
+
const profiles = objectRecord(objectRecord(instructionSetValue)?.profiles);
|
|
190
|
+
if (!profiles)
|
|
191
|
+
continue;
|
|
192
|
+
for (const [profileSlug, profileValue] of Object.entries(profiles)) {
|
|
193
|
+
const versions = objectRecord(objectRecord(profileValue)?.versions);
|
|
194
|
+
if (!versions)
|
|
195
|
+
continue;
|
|
196
|
+
for (const [versionKey, versionValue] of Object.entries(versions)) {
|
|
197
|
+
const components = objectRecord(objectRecord(versionValue)?.components);
|
|
198
|
+
if (!components)
|
|
199
|
+
continue;
|
|
200
|
+
const pathPrefix = [
|
|
201
|
+
'instructionSets',
|
|
202
|
+
setSlug,
|
|
203
|
+
'profiles',
|
|
204
|
+
profileSlug,
|
|
205
|
+
'versions',
|
|
206
|
+
versionKey,
|
|
207
|
+
'components',
|
|
208
|
+
].reduce(childPath, '');
|
|
209
|
+
validateInstructionSetComponentKeys(Object.keys(components), pathPrefix);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function validateLockSlugs(value) {
|
|
215
|
+
const instructionSets = objectRecord(objectRecord(value)?.instructionSets);
|
|
216
|
+
if (!instructionSets)
|
|
217
|
+
return;
|
|
218
|
+
for (const [setSlug, instructionSetValue] of Object.entries(instructionSets)) {
|
|
219
|
+
if (!INSTRUCTION_SET_SLUG.test(setSlug)) {
|
|
220
|
+
const path = childPath(childPath('', 'instructionSets'), setSlug);
|
|
221
|
+
throw new LockParseError(`lock_set_slug_invalid:${path}`, path);
|
|
222
|
+
}
|
|
223
|
+
const instructionSet = objectRecord(instructionSetValue);
|
|
224
|
+
const defaultSlug = instructionSet?.default;
|
|
225
|
+
if (typeof defaultSlug === 'string' && !INSTRUCTION_SET_PROFILE_SLUG.test(defaultSlug)) {
|
|
226
|
+
const path = [
|
|
227
|
+
'instructionSets',
|
|
228
|
+
setSlug,
|
|
229
|
+
'default',
|
|
230
|
+
].reduce(childPath, '');
|
|
231
|
+
throw new LockParseError(`lock_default_slug_invalid:${path}`, path);
|
|
232
|
+
}
|
|
233
|
+
const profiles = objectRecord(instructionSet?.profiles);
|
|
234
|
+
if (!profiles)
|
|
235
|
+
continue;
|
|
236
|
+
for (const profileSlug of Object.keys(profiles)) {
|
|
237
|
+
if (INSTRUCTION_SET_PROFILE_SLUG.test(profileSlug))
|
|
238
|
+
continue;
|
|
239
|
+
const path = [
|
|
240
|
+
'instructionSets',
|
|
241
|
+
setSlug,
|
|
242
|
+
'profiles',
|
|
243
|
+
profileSlug,
|
|
244
|
+
].reduce(childPath, '');
|
|
245
|
+
throw new LockParseError(`lock_profile_slug_invalid:${path}`, path);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function validateHelperPaths(value) {
|
|
250
|
+
const helpers = objectRecord(objectRecord(value)?.helpers);
|
|
251
|
+
if (!helpers)
|
|
252
|
+
return;
|
|
253
|
+
const helperPathsByWindowsIdentity = new Map();
|
|
254
|
+
for (const helperPath of Object.keys(helpers)) {
|
|
255
|
+
const pathIdentity = windowsPathIdentity(helperPath);
|
|
256
|
+
const collidingPath = helperPathsByWindowsIdentity.get(pathIdentity);
|
|
257
|
+
if (collidingPath !== undefined) {
|
|
258
|
+
throw new LockParseError(`instruction_set_lock_helper_path_collision:${collidingPath},${helperPath}`);
|
|
259
|
+
}
|
|
260
|
+
helperPathsByWindowsIdentity.set(pathIdentity, helperPath);
|
|
261
|
+
if (INSTRUCTION_SET_HELPER_PATH.test(helperPath))
|
|
262
|
+
continue;
|
|
263
|
+
const path = childPath(childPath('', 'helpers'), helperPath);
|
|
264
|
+
throw new LockParseError(`lock_helper_path_invalid:${path}`, path);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function validatePinSpecifiers(value) {
|
|
268
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
269
|
+
return;
|
|
270
|
+
const pins = value.pins;
|
|
271
|
+
if (!Array.isArray(pins))
|
|
272
|
+
return;
|
|
273
|
+
for (const [index, pin] of pins.entries()) {
|
|
274
|
+
if (typeof pin !== 'string')
|
|
275
|
+
continue;
|
|
276
|
+
const path = childPath(childPath('', 'pins'), String(index));
|
|
277
|
+
try {
|
|
278
|
+
const specifier = parseSpecifier(pin);
|
|
279
|
+
if (specifier.versionNumber === undefined) {
|
|
280
|
+
throw new SpecifierParseError('specifier_invalid_version');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
if (!(error instanceof SpecifierParseError))
|
|
285
|
+
throw error;
|
|
286
|
+
throw new LockParseError(`lock_pin_invalid:${path}:${error.code}`, path);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function validateUniqueIds(lock) {
|
|
291
|
+
const instructionSetIds = new Set();
|
|
292
|
+
const profileVersionIds = new Set();
|
|
293
|
+
for (const [setSlug, instructionSet] of Object.entries(lock.instructionSets)) {
|
|
294
|
+
const instructionSetId = instructionSet.instructionSetId.toLowerCase();
|
|
295
|
+
if (instructionSetIds.has(instructionSetId)) {
|
|
296
|
+
const path = [
|
|
297
|
+
'instructionSets',
|
|
298
|
+
setSlug,
|
|
299
|
+
'instructionSetId',
|
|
300
|
+
].reduce(childPath, '');
|
|
301
|
+
throw new LockParseError(`lock_instruction_set_id_duplicate:${path}`, path);
|
|
302
|
+
}
|
|
303
|
+
instructionSetIds.add(instructionSetId);
|
|
304
|
+
for (const [profileSlug, profile] of Object.entries(instructionSet.profiles)) {
|
|
305
|
+
for (const [versionKey, version] of Object.entries(profile.versions)) {
|
|
306
|
+
const profileVersionId = version.profileVersionId.toLowerCase();
|
|
307
|
+
if (profileVersionIds.has(profileVersionId)) {
|
|
308
|
+
const path = [
|
|
309
|
+
'instructionSets',
|
|
310
|
+
setSlug,
|
|
311
|
+
'profiles',
|
|
312
|
+
profileSlug,
|
|
313
|
+
'versions',
|
|
314
|
+
versionKey,
|
|
315
|
+
'profileVersionId',
|
|
316
|
+
].reduce(childPath, '');
|
|
317
|
+
throw new LockParseError(`lock_profile_version_id_duplicate:${path}`, path);
|
|
318
|
+
}
|
|
319
|
+
profileVersionIds.add(profileVersionId);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function validateLockValue(value) {
|
|
325
|
+
if (value !== null &&
|
|
326
|
+
typeof value === 'object' &&
|
|
327
|
+
!Array.isArray(value) &&
|
|
328
|
+
typeof value.lockfileVersion === 'number' &&
|
|
329
|
+
value.lockfileVersion !== 1) {
|
|
330
|
+
throw new LockParseError('lock_unsupported_version');
|
|
331
|
+
}
|
|
332
|
+
validateComponentKeys(value);
|
|
333
|
+
validateLockSlugs(value);
|
|
334
|
+
validateHelperPaths(value);
|
|
335
|
+
validatePinSpecifiers(value);
|
|
336
|
+
const violation = firstSchemaViolation(value, rootSchema, '');
|
|
337
|
+
if (violation) {
|
|
338
|
+
throw new LockParseError(`lock_schema_violation:${violation}`, violation);
|
|
339
|
+
}
|
|
340
|
+
const lock = value;
|
|
341
|
+
validateUniqueIds(lock);
|
|
342
|
+
for (const [setSlug, instructionSet] of Object.entries(lock.instructionSets)) {
|
|
343
|
+
for (const [profileSlug, profile] of Object.entries(instructionSet.profiles)) {
|
|
344
|
+
for (const [versionKey, version] of Object.entries(profile.versions)) {
|
|
345
|
+
if (versionKey !== `v${version.versionNumber}`) {
|
|
346
|
+
const path = childPath(childPath(childPath(childPath(childPath('', 'instructionSets'), setSlug), 'profiles'), profileSlug), 'versions');
|
|
347
|
+
const versionPath = childPath(path, versionKey);
|
|
348
|
+
throw new LockParseError(`lock_schema_violation:${versionPath}`, versionPath);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (profile.production !== null && !Object.hasOwn(profile.versions, profile.production)) {
|
|
352
|
+
throw new LockParseError('lock_production_not_a_version', childPath(childPath(childPath(childPath('', 'instructionSets'), setSlug), 'profiles'), profileSlug));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return lock;
|
|
357
|
+
}
|
|
358
|
+
export function parseLock(text) {
|
|
359
|
+
let value;
|
|
360
|
+
try {
|
|
361
|
+
value = JSON.parse(text);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
throw new LockParseError('lock_invalid_json');
|
|
365
|
+
}
|
|
366
|
+
return validateLockValue(value);
|
|
367
|
+
}
|
|
368
|
+
function orderedObject(entries) {
|
|
369
|
+
return new Map(entries);
|
|
370
|
+
}
|
|
371
|
+
function orderedRecord(record, mapValue) {
|
|
372
|
+
return orderedObject(Object.keys(record).sort().map(key => [key, mapValue(record[key])]));
|
|
373
|
+
}
|
|
374
|
+
function stringifyOrdered(value, depth = 0) {
|
|
375
|
+
if (value instanceof Map) {
|
|
376
|
+
if (value.size === 0)
|
|
377
|
+
return '{}';
|
|
378
|
+
const entries = [...value.entries()].map(([key, child]) => `${' '.repeat(depth + 1)}${JSON.stringify(key)}: ${stringifyOrdered(child, depth + 1)}`);
|
|
379
|
+
return `{\n${entries.join(',\n')}\n${' '.repeat(depth)}}`;
|
|
380
|
+
}
|
|
381
|
+
if (Array.isArray(value)) {
|
|
382
|
+
if (value.length === 0)
|
|
383
|
+
return '[]';
|
|
384
|
+
const items = value.map(item => `${' '.repeat(depth + 1)}${stringifyOrdered(item, depth + 1)}`);
|
|
385
|
+
return `[\n${items.join(',\n')}\n${' '.repeat(depth)}]`;
|
|
386
|
+
}
|
|
387
|
+
return JSON.stringify(value);
|
|
388
|
+
}
|
|
389
|
+
export function serializeLock(lock) {
|
|
390
|
+
const validLock = validateLockValue(lock);
|
|
391
|
+
const instructionSets = orderedRecord(validLock.instructionSets, instructionSet => orderedObject([
|
|
392
|
+
['instructionSetId', instructionSet.instructionSetId],
|
|
393
|
+
['default', instructionSet.default],
|
|
394
|
+
['profiles', orderedRecord(instructionSet.profiles, profile => orderedObject([
|
|
395
|
+
...(profile.modelConfigIdentity === undefined ? [] : [['modelConfigIdentity', profile.modelConfigIdentity]]),
|
|
396
|
+
['production', profile.production],
|
|
397
|
+
['versions', orderedObject(Object.entries(profile.versions)
|
|
398
|
+
.sort((left, right) => left[1].versionNumber - right[1].versionNumber)
|
|
399
|
+
.map(([versionKey, version]) => [versionKey, orderedObject([
|
|
400
|
+
['profileVersionId', version.profileVersionId],
|
|
401
|
+
['versionNumber', version.versionNumber],
|
|
402
|
+
['digest', version.digest],
|
|
403
|
+
['components', orderedRecord(version.components, digest => digest)],
|
|
404
|
+
['syncedAt', version.syncedAt],
|
|
405
|
+
])]))],
|
|
406
|
+
]))],
|
|
407
|
+
]));
|
|
408
|
+
const entries = [
|
|
409
|
+
['lockfileVersion', 1],
|
|
410
|
+
['project', validLock.project],
|
|
411
|
+
['instructionSets', instructionSets],
|
|
412
|
+
];
|
|
413
|
+
if (validLock.helpers)
|
|
414
|
+
entries.push([
|
|
415
|
+
'helpers',
|
|
416
|
+
orderedRecord(validLock.helpers, digest => digest),
|
|
417
|
+
]);
|
|
418
|
+
if (validLock.pins)
|
|
419
|
+
entries.push(['pins', [...validLock.pins]]);
|
|
420
|
+
return `${stringifyOrdered(orderedObject(entries))}\n`;
|
|
421
|
+
}
|
|
422
|
+
export function parseSpecifier(text) {
|
|
423
|
+
if (text.length === 0)
|
|
424
|
+
throw new SpecifierParseError('specifier_empty');
|
|
425
|
+
const firstSlash = text.indexOf('/');
|
|
426
|
+
if (firstSlash === -1) {
|
|
427
|
+
if (text.includes('@'))
|
|
428
|
+
throw new SpecifierParseError('specifier_version_without_profile');
|
|
429
|
+
if (!INSTRUCTION_SET_SLUG.test(text))
|
|
430
|
+
throw new SpecifierParseError('specifier_invalid_set');
|
|
431
|
+
return { set: text };
|
|
432
|
+
}
|
|
433
|
+
const set = text.slice(0, firstSlash);
|
|
434
|
+
if (!INSTRUCTION_SET_SLUG.test(set))
|
|
435
|
+
throw new SpecifierParseError('specifier_invalid_set');
|
|
436
|
+
const profileAndVersion = text.slice(firstSlash + 1);
|
|
437
|
+
if (profileAndVersion.length === 0 || profileAndVersion.startsWith('@')) {
|
|
438
|
+
throw new SpecifierParseError('specifier_profile_missing');
|
|
439
|
+
}
|
|
440
|
+
const versionSuffix = /@v([0-9]+)$/u.exec(profileAndVersion);
|
|
441
|
+
if (versionSuffix && !/^[1-9][0-9]*$/u.test(versionSuffix[1])) {
|
|
442
|
+
throw new SpecifierParseError('specifier_invalid_version');
|
|
443
|
+
}
|
|
444
|
+
const profile = versionSuffix
|
|
445
|
+
? profileAndVersion.slice(0, versionSuffix.index)
|
|
446
|
+
: profileAndVersion;
|
|
447
|
+
if (profile.length === 0)
|
|
448
|
+
throw new SpecifierParseError('specifier_profile_missing');
|
|
449
|
+
if (/\s/u.test(profile))
|
|
450
|
+
throw new SpecifierParseError('specifier_invalid_profile');
|
|
451
|
+
if (!versionSuffix)
|
|
452
|
+
return { set, profile };
|
|
453
|
+
const versionNumber = Number(versionSuffix[1]);
|
|
454
|
+
if (versionNumber < 1)
|
|
455
|
+
throw new SpecifierParseError('specifier_invalid_version');
|
|
456
|
+
if (versionNumber > MAX_VERSION_NUMBER)
|
|
457
|
+
throw new SpecifierParseError('specifier_invalid_version');
|
|
458
|
+
return { set, profile, versionNumber };
|
|
459
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export declare const instructionSetLockSchemaV1: {
|
|
2
|
+
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
3
|
+
readonly $id: "https://orizu.ai/schemas/instruction-set-lock/v1";
|
|
4
|
+
readonly title: "Orizu instruction set Lock v1";
|
|
5
|
+
readonly type: "object";
|
|
6
|
+
readonly required: readonly ["lockfileVersion", "project", "instructionSets"];
|
|
7
|
+
readonly additionalProperties: false;
|
|
8
|
+
readonly properties: {
|
|
9
|
+
readonly lockfileVersion: {
|
|
10
|
+
readonly const: 1;
|
|
11
|
+
};
|
|
12
|
+
readonly project: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*/[a-z0-9]+(?:-[a-z0-9]+)*$";
|
|
15
|
+
};
|
|
16
|
+
readonly instructionSets: {
|
|
17
|
+
readonly type: "object";
|
|
18
|
+
readonly additionalProperties: false;
|
|
19
|
+
readonly patternProperties: {
|
|
20
|
+
readonly "^[a-z0-9]+(?:-[a-z0-9]+)*$": {
|
|
21
|
+
readonly $ref: "#/$defs/instructionSet";
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
readonly helpers: {
|
|
26
|
+
readonly type: "object";
|
|
27
|
+
readonly propertyNames: {
|
|
28
|
+
readonly pattern: "^helpers\\/(?!\\.{1,2}(?:\\/|$))(?!.*\\/\\.{1,2}(?:\\/|$))[A-Za-z0-9._-]+(?:\\/[A-Za-z0-9._-]+)*$";
|
|
29
|
+
};
|
|
30
|
+
readonly additionalProperties: {
|
|
31
|
+
readonly $ref: "#/$defs/sha256";
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
readonly pins: {
|
|
35
|
+
readonly type: "array";
|
|
36
|
+
readonly uniqueItems: true;
|
|
37
|
+
readonly items: {
|
|
38
|
+
readonly type: "string";
|
|
39
|
+
readonly pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*/[^\\s]+@v[1-9][0-9]*$";
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
readonly $defs: {
|
|
44
|
+
readonly sha256: {
|
|
45
|
+
readonly type: "string";
|
|
46
|
+
readonly pattern: "^sha256:[0-9a-f]{64}$";
|
|
47
|
+
};
|
|
48
|
+
readonly instructionSet: {
|
|
49
|
+
readonly type: "object";
|
|
50
|
+
readonly required: readonly ["instructionSetId", "default", "profiles"];
|
|
51
|
+
readonly additionalProperties: false;
|
|
52
|
+
readonly properties: {
|
|
53
|
+
readonly instructionSetId: {
|
|
54
|
+
readonly type: "string";
|
|
55
|
+
readonly format: "uuid";
|
|
56
|
+
readonly pattern: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89aAbB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$";
|
|
57
|
+
};
|
|
58
|
+
readonly default: {
|
|
59
|
+
readonly type: "string";
|
|
60
|
+
readonly pattern: "^[a-z0-9][a-z0-9._-]*__[a-z0-9][a-z0-9._-]*$";
|
|
61
|
+
};
|
|
62
|
+
readonly profiles: {
|
|
63
|
+
readonly type: "object";
|
|
64
|
+
readonly minProperties: 1;
|
|
65
|
+
readonly additionalProperties: false;
|
|
66
|
+
readonly patternProperties: {
|
|
67
|
+
readonly "^[a-z0-9][a-z0-9._-]*__[a-z0-9][a-z0-9._-]*$": {
|
|
68
|
+
readonly $ref: "#/$defs/profile";
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
readonly profile: {
|
|
75
|
+
readonly type: "object";
|
|
76
|
+
readonly required: readonly ["production", "versions"];
|
|
77
|
+
readonly additionalProperties: false;
|
|
78
|
+
readonly properties: {
|
|
79
|
+
readonly modelConfigIdentity: {
|
|
80
|
+
readonly type: "string";
|
|
81
|
+
readonly minLength: 1;
|
|
82
|
+
};
|
|
83
|
+
readonly production: {
|
|
84
|
+
readonly type: readonly ["string", "null"];
|
|
85
|
+
readonly pattern: "^v[1-9][0-9]*$";
|
|
86
|
+
};
|
|
87
|
+
readonly versions: {
|
|
88
|
+
readonly type: "object";
|
|
89
|
+
readonly minProperties: 1;
|
|
90
|
+
readonly additionalProperties: false;
|
|
91
|
+
readonly patternProperties: {
|
|
92
|
+
readonly "^v[1-9][0-9]*$": {
|
|
93
|
+
readonly $ref: "#/$defs/version";
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
readonly version: {
|
|
100
|
+
readonly type: "object";
|
|
101
|
+
readonly required: readonly ["profileVersionId", "versionNumber", "digest", "components", "syncedAt"];
|
|
102
|
+
readonly additionalProperties: false;
|
|
103
|
+
readonly properties: {
|
|
104
|
+
readonly profileVersionId: {
|
|
105
|
+
readonly type: "string";
|
|
106
|
+
readonly format: "uuid";
|
|
107
|
+
readonly pattern: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89aAbB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$";
|
|
108
|
+
};
|
|
109
|
+
readonly versionNumber: {
|
|
110
|
+
readonly type: "integer";
|
|
111
|
+
readonly minimum: 1;
|
|
112
|
+
readonly maximum: 2147483647;
|
|
113
|
+
};
|
|
114
|
+
readonly digest: {
|
|
115
|
+
readonly $ref: "#/$defs/sha256";
|
|
116
|
+
};
|
|
117
|
+
readonly components: {
|
|
118
|
+
readonly type: "object";
|
|
119
|
+
readonly minProperties: 1;
|
|
120
|
+
readonly propertyNames: {
|
|
121
|
+
readonly pattern: "^(?!\\.)[A-Za-z0-9._-]+$";
|
|
122
|
+
};
|
|
123
|
+
readonly additionalProperties: {
|
|
124
|
+
readonly $ref: "#/$defs/sha256";
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
readonly syncedAt: {
|
|
128
|
+
readonly type: "string";
|
|
129
|
+
readonly format: "date-time";
|
|
130
|
+
readonly pattern: "^(?:(?:[0-9]{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12][0-9]|3[01])|(?:0[469]|11)-(?:0[1-9]|[12][0-9]|30)|02-(?:0[1-9]|1[0-9]|2[0-8])))|(?:(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:00|0[48]|[2468][048]|[13579][26])00)-02-29))T(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\\.[0-9]{3}Z$";
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=schema.v1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.v1.d.ts","sourceRoot":"","sources":["../../src/instruction-set-lock/schema.v1.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0J7B,CAAA"}
|