@skill-harness/adapters 0.10.0 → 0.12.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/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # @skill-harness/adapters
2
2
 
3
3
  Harness adapters for [skill-harness](https://github.com/mojomanyana/skill-harness):
4
- the `pi` runner + `claude-code` judge routing.
4
+ the `pi` runner + `claude-code` judge routing, the frozen pi-daddy 0.17/v2
5
+ normalizer, and the separately pinned production ledger-v3 normalizer.
5
6
 
6
7
  Internal — use the `skill-harness` CLI. See the repo for docs.
7
8
 
@@ -33,6 +33,8 @@ type Schema = Record<string, unknown>;
33
33
  * a keyword fails loudly rather than validating less than it claims.
34
34
  */
35
35
  export declare function assertSupportedSchema(schema: unknown, label: string, path?: string): void;
36
+ /** V3-only evaluator profile; the frozen v2 profile above remains unchanged. */
37
+ export declare function assertSupportedSchemaV3(schema: unknown, label: string, path?: string): void;
36
38
  /**
37
39
  * Validate `value` against `schema`. Returns every violation found; an empty
38
40
  * array means the instance satisfies the pinned contract.
@@ -45,6 +47,10 @@ export declare function assertSupportedSchema(schema: unknown, label: string, pa
45
47
  export declare function validateClosedSchema(schema: Schema, value: unknown, options?: {
46
48
  knownFieldNames?: ReadonlySet<string>;
47
49
  }): SchemaViolation[];
50
+ /** Evaluate the additional closed constructs used by the separately pinned v3 schema. */
51
+ export declare function validateClosedSchemaV3(schema: Schema, value: unknown, options?: {
52
+ knownFieldNames?: ReadonlySet<string>;
53
+ }): SchemaViolation[];
48
54
  /** Every property name declared anywhere in the document — safe to echo. */
49
55
  export declare function declaredPropertyNames(schema: unknown): Set<string>;
50
56
  export {};
@@ -31,6 +31,11 @@ const SUPPORTED_KEYWORDS = new Set([
31
31
  // value constraints
32
32
  "enum", "const", "minLength", "maxLength", "minimum", "pattern", "format",
33
33
  ]);
34
+ /** Ledger v3 adds only closed composition/conditionals and property-name schemas. */
35
+ const V3_SUPPORTED_KEYWORDS = new Set([
36
+ ...SUPPORTED_KEYWORDS,
37
+ "allOf", "anyOf", "if", "then", "propertyNames", "minItems", "maxItems",
38
+ ]);
34
39
  /**
35
40
  * The shape each supported keyword must have. A keyword whose *name* is known but
36
41
  * whose *value* has an unexpected shape is the same hole as an unknown keyword:
@@ -40,6 +45,11 @@ const SUPPORTED_KEYWORDS = new Set([
40
45
  const KEYWORD_SHAPES = {
41
46
  $ref: { check: (value) => typeof value === "string", expected: "a string" },
42
47
  oneOf: { check: (value) => Array.isArray(value) && value.length > 0, expected: "a non-empty array" },
48
+ allOf: { check: (value) => Array.isArray(value) && value.length > 0, expected: "a non-empty array" },
49
+ anyOf: { check: (value) => Array.isArray(value) && value.length > 0, expected: "a non-empty array" },
50
+ if: { check: (value) => isSchemaObject(value), expected: "a schema object" },
51
+ then: { check: (value) => isSchemaObject(value), expected: "a schema object" },
52
+ propertyNames: { check: (value) => isSchemaObject(value), expected: "a schema object" },
43
53
  type: { check: (value) => typeof value === "string" || (Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "string")), expected: "a string or array of strings" },
44
54
  properties: { check: (value) => isSchemaObject(value), expected: "an object" },
45
55
  required: { check: (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string"), expected: "an array of strings" },
@@ -49,6 +59,8 @@ const KEYWORD_SHAPES = {
49
59
  minLength: { check: (value) => typeof value === "number", expected: "a number" },
50
60
  maxLength: { check: (value) => typeof value === "number", expected: "a number" },
51
61
  minimum: { check: (value) => typeof value === "number", expected: "a number" },
62
+ minItems: { check: (value) => Number.isInteger(value) && Number(value) >= 0, expected: "a non-negative integer" },
63
+ maxItems: { check: (value) => Number.isInteger(value) && Number(value) >= 0, expected: "a non-negative integer" },
52
64
  pattern: { check: (value) => typeof value === "string", expected: "a string" },
53
65
  format: { check: (value) => typeof value === "string", expected: "a string" },
54
66
  // `const` may legitimately be any JSON value, including null.
@@ -61,12 +73,20 @@ const SUPPORTED_TYPES = new Set(["object", "array", "string", "number", "integer
61
73
  * a keyword fails loudly rather than validating less than it claims.
62
74
  */
63
75
  export function assertSupportedSchema(schema, label, path = "#") {
76
+ assertSchemaSupported(schema, label, path, false);
77
+ }
78
+ /** V3-only evaluator profile; the frozen v2 profile above remains unchanged. */
79
+ export function assertSupportedSchemaV3(schema, label, path = "#") {
80
+ assertSchemaSupported(schema, label, path, true);
81
+ }
82
+ function assertSchemaSupported(schema, label, path, v3) {
64
83
  if (typeof schema !== "object" || schema === null || Array.isArray(schema)) {
65
84
  throw new Error(`${label} is not a JSON Schema object at ${path}`);
66
85
  }
67
86
  const node = schema;
87
+ const supported = v3 ? V3_SUPPORTED_KEYWORDS : SUPPORTED_KEYWORDS;
68
88
  for (const keyword of Object.keys(node)) {
69
- if (!SUPPORTED_KEYWORDS.has(keyword)) {
89
+ if (!supported.has(keyword)) {
70
90
  throw new Error(`${label} uses unsupported JSON Schema keyword \`${keyword}\` at ${path}; the closed-contract evaluator refuses to validate less than the schema declares`);
71
91
  }
72
92
  const shape = KEYWORD_SHAPES[keyword];
@@ -94,15 +114,20 @@ export function assertSupportedSchema(schema, label, path = "#") {
94
114
  }
95
115
  }
96
116
  for (const [name, entry] of Object.entries(object(node.$defs) ?? {}))
97
- assertSupportedSchema(entry, label, `${path}/$defs/${name}`);
98
- for (const [index, entry] of (Array.isArray(node.oneOf) ? node.oneOf : []).entries())
99
- assertSupportedSchema(entry, label, `${path}/oneOf/${index}`);
117
+ assertSchemaSupported(entry, label, `${path}/$defs/${name}`, v3);
118
+ for (const keyword of ["oneOf", "allOf", "anyOf"]) {
119
+ for (const [index, entry] of (Array.isArray(node[keyword]) ? node[keyword] : []).entries()) {
120
+ assertSchemaSupported(entry, label, `${path}/${keyword}/${index}`, v3);
121
+ }
122
+ }
100
123
  for (const [name, entry] of Object.entries(object(node.properties) ?? {}))
101
- assertSupportedSchema(entry, label, `${path}/properties/${name}`);
102
- if (node.items !== undefined)
103
- assertSupportedSchema(node.items, label, `${path}/items`);
124
+ assertSchemaSupported(entry, label, `${path}/properties/${name}`, v3);
125
+ for (const keyword of ["items", "propertyNames", "if", "then"]) {
126
+ if (node[keyword] !== undefined)
127
+ assertSchemaSupported(node[keyword], label, `${path}/${keyword}`, v3);
128
+ }
104
129
  if (node.additionalProperties !== undefined && node.additionalProperties !== false && node.additionalProperties !== true) {
105
- assertSupportedSchema(node.additionalProperties, label, `${path}/additionalProperties`);
130
+ assertSchemaSupported(node.additionalProperties, label, `${path}/additionalProperties`, v3);
106
131
  }
107
132
  }
108
133
  /**
@@ -117,6 +142,10 @@ export function assertSupportedSchema(schema, label, path = "#") {
117
142
  export function validateClosedSchema(schema, value, options = {}) {
118
143
  return validate(schema, schema, value, "", options.knownFieldNames ?? new Set());
119
144
  }
145
+ /** Evaluate the additional closed constructs used by the separately pinned v3 schema. */
146
+ export function validateClosedSchemaV3(schema, value, options = {}) {
147
+ return validate(schema, schema, value, "", options.knownFieldNames ?? new Set());
148
+ }
120
149
  /** Every property name declared anywhere in the document — safe to echo. */
121
150
  export function declaredPropertyNames(schema) {
122
151
  const names = new Set();
@@ -130,10 +159,13 @@ export function declaredPropertyNames(schema) {
130
159
  }
131
160
  for (const entry of Object.values(object(current.$defs) ?? {}))
132
161
  walk(entry);
133
- for (const entry of Array.isArray(current.oneOf) ? current.oneOf : [])
134
- walk(entry);
135
- if (current.items !== undefined)
136
- walk(current.items);
162
+ for (const keyword of ["oneOf", "allOf", "anyOf"]) {
163
+ for (const entry of Array.isArray(current[keyword]) ? current[keyword] : [])
164
+ walk(entry);
165
+ }
166
+ for (const keyword of ["items", "propertyNames", "if", "then"])
167
+ if (current[keyword] !== undefined)
168
+ walk(current[keyword]);
137
169
  if (current.additionalProperties && typeof current.additionalProperties === "object")
138
170
  walk(current.additionalProperties);
139
171
  };
@@ -146,6 +178,18 @@ function validate(root, schema, value, path, known) {
146
178
  return validate(root, resolved, value, path, known);
147
179
  }
148
180
  const violations = [];
181
+ if (Array.isArray(schema.allOf)) {
182
+ for (const branch of schema.allOf)
183
+ violations.push(...validate(root, branch, value, path, known));
184
+ }
185
+ if (Array.isArray(schema.anyOf)) {
186
+ const branches = schema.anyOf.map((branch) => validate(root, branch, value, path, known));
187
+ if (!branches.some((branch) => branch.length === 0))
188
+ violations.push(...bestBranch(root, schema.anyOf, branches, value, path));
189
+ }
190
+ if (schema.if !== undefined && validate(root, schema.if, value, path, known).length === 0 && schema.then !== undefined) {
191
+ violations.push(...validate(root, schema.then, value, path, known));
192
+ }
149
193
  const types = typeList(schema);
150
194
  if (types.length && !types.some((type) => matchesType(type, value))) {
151
195
  return [{ path, message: `must be ${describeTypes(types)}` }];
@@ -169,8 +213,16 @@ function validate(root, schema, value, path, known) {
169
213
  violations.push(...validateString(schema, value, path));
170
214
  if (typeof value === "number")
171
215
  violations.push(...validateNumber(schema, value, path));
172
- if (Array.isArray(value) && schema.items !== undefined) {
173
- value.forEach((entry, index) => violations.push(...validate(root, schema.items, entry, `${path}[${index}]`, known)));
216
+ if (Array.isArray(value)) {
217
+ if (typeof schema.minItems === "number" && value.length < schema.minItems) {
218
+ violations.push({ path, message: `must contain at least ${schema.minItems} item(s)` });
219
+ }
220
+ if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
221
+ violations.push({ path, message: `must contain at most ${schema.maxItems} item(s)` });
222
+ }
223
+ if (schema.items !== undefined) {
224
+ value.forEach((entry, index) => violations.push(...validate(root, schema.items, entry, `${path}[${index}]`, known)));
225
+ }
174
226
  }
175
227
  const record = object(value);
176
228
  if (record)
@@ -180,6 +232,10 @@ function validate(root, schema, value, path, known) {
180
232
  function validateObject(root, schema, record, path, known) {
181
233
  const violations = [];
182
234
  const properties = object(schema.properties) ?? {};
235
+ if (schema.propertyNames !== undefined) {
236
+ for (const name of Object.keys(record))
237
+ violations.push(...validate(root, schema.propertyNames, name, path, known));
238
+ }
183
239
  for (const name of (Array.isArray(schema.required) ? schema.required : [])) {
184
240
  if (!Object.hasOwn(record, name))
185
241
  violations.push({ path: child(path, name), message: "is required" });
package/dist/index.d.ts CHANGED
@@ -2,4 +2,6 @@ import type { HarnessAdapter } from "@skill-harness/core";
2
2
  import { piAdapter } from "./pi.js";
3
3
  export declare function getAdapter(name: string): HarnessAdapter;
4
4
  export { piAdapter };
5
+ export * from "./prompt-provenance.js";
5
6
  export * from "./trajectory.js";
7
+ export * from "./pi-daddy-ledger-v3.js";
package/dist/index.js CHANGED
@@ -14,5 +14,7 @@ export function getAdapter(name) {
14
14
  return a;
15
15
  }
16
16
  export { piAdapter };
17
+ export * from "./prompt-provenance.js";
17
18
  export * from "./trajectory.js";
19
+ export * from "./pi-daddy-ledger-v3.js";
18
20
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
- /** pi-daddy commit whose contract artifact this schema was taken from. */
2
- export declare const PI_DADDY_CONTRACT_COMMIT = "1948b9406c13c9730f2fc103e68023d6e58c5e85";
1
+ /** pi-daddy commit whose contract artifacts this schema was taken from. */
2
+ export declare const PI_DADDY_CONTRACT_COMMIT = "c364a6717e3d5e369ecd3298b9cbb595eb94d9b2";
3
3
  /** SHA-256 of the byte-exact producer schema file this object was generated from. */
4
- export declare const PI_DADDY_LEDGER_V2_SCHEMA_SHA256 = "69c3a6856481b9250587c5785a8aadda87baba6cb03c79b209cff4f55f70a81c";
4
+ export declare const PI_DADDY_LEDGER_V2_SCHEMA_SHA256 = "3862bc451c25393dd40b198c62a8f94a3f58784e31da6dff05e3f06be71a3f86";
5
5
  /** pi-daddy's canonical, closed ledgerVersion 2 event schema (JSON Schema draft 2020-12). */
6
6
  export declare const PI_DADDY_LEDGER_V2_SCHEMA: {
7
7
  readonly $schema: "https://json-schema.org/draft/2020-12/schema";
@@ -109,7 +109,7 @@ export declare const PI_DADDY_LEDGER_V2_SCHEMA: {
109
109
  };
110
110
  readonly refusalCode: {
111
111
  readonly type: "string";
112
- readonly enum: readonly ["CAPABILITY_ESCALATION", "GRANT_ID_MALFORMED", "DEFINITION_NOT_AUTHORIZED", "UNDECLARED_TOOLS", "UNKNOWN_TOOL", "GATED_UNAPPROVED", "APPROVAL_EXPIRED", "APPROVAL_SCOPE_MISMATCH", "APPROVAL_FLOW_FAILED", "DEPTH_EXCEEDED", "FANOUT_EXCEEDED", "EXECUTOR_UNAVAILABLE", "CHILD_TIMED_OUT", "CHILD_CANCELLED", "CHILD_EXIT_NONZERO", "TASK_MISSING", "UNKNOWN_DEFINITION", "CEILING_PATTERNS_UNRESOLVED", "NARROWING_VIOLATED", "DEFINITION_UNREADABLE", "CORRELATION_TOO_LARGE", "CORRELATION_INVALID", "LEDGER_WRITE_FAILED", "FANOUT_FAILED", "WORKSPACE_NOT_REGISTERED", "WORKSPACE_WRITE_CONFLICT", "WORKSPACE_LEASE_STALE", "CHECK_NOT_CONFIGURED", "CHECK_CONFIGURATION_INVALID", "CHECK_IDENTITY_UNAVAILABLE", "CHECK_IDENTITY_MISMATCH"];
112
+ readonly enum: readonly ["CAPABILITY_ESCALATION", "GRANT_ID_MALFORMED", "DEFINITION_NOT_AUTHORIZED", "UNDECLARED_TOOLS", "UNKNOWN_TOOL", "GATED_UNAPPROVED", "APPROVAL_EXPIRED", "APPROVAL_SCOPE_MISMATCH", "APPROVAL_FLOW_FAILED", "DEPTH_EXCEEDED", "FANOUT_EXCEEDED", "EXECUTOR_UNAVAILABLE", "CHILD_TIMED_OUT", "CHILD_CANCELLED", "CHILD_EXIT_NONZERO", "TASK_MISSING", "UNKNOWN_DEFINITION", "CEILING_PATTERNS_UNRESOLVED", "NARROWING_VIOLATED", "DEFINITION_UNREADABLE", "CORRELATION_TOO_LARGE", "CORRELATION_INVALID", "LEDGER_WRITE_FAILED", "FANOUT_FAILED", "WORKSPACE_NOT_REGISTERED", "WORKSPACE_NOT_AUTHORIZED", "WORKSPACE_WRITE_CONFLICT", "WORKSPACE_LEASE_STALE", "CHECK_NOT_CONFIGURED", "CHECK_CONFIGURATION_INVALID", "CHECK_IDENTITY_UNAVAILABLE", "CHECK_IDENTITY_MISMATCH"];
113
113
  };
114
114
  readonly refusal: {
115
115
  readonly type: "object";
@@ -1,18 +1,19 @@
1
1
  // GENERATED by scripts/vendor-pi-daddy-contract.mjs — do not edit by hand.
2
2
  //
3
3
  // The runtime copy of pi-daddy's canonical `ledgerVersion: 2` JSON Schema, pinned to
4
- // producer commit 1948b9406c13c9730f2fc103e68023d6e58c5e85.
4
+ // producer commit c364a6717e3d5e369ecd3298b9cbb595eb94d9b2.
5
5
  // It is a module rather than a file read so it survives bundling (the pi extension is a
6
6
  // committed esbuild bundle) and so the published package needs no data asset.
7
7
  //
8
- // contracts/pi-daddy/ledger/v2/ holds the byte-exact producer artifact and its recorded
9
- // SHA-256 digests; packages/adapters/test/pi-daddy-contract.test.ts asserts those digests
10
- // and that this object still deep-equals the vendored bytes. Re-pin with:
8
+ // contracts/pi-daddy/ledger/v2/ holds the byte-exact producer artifacts and their
9
+ // SHA-256 digests; packages/adapters/test/pi-daddy-contract.test.ts asserts those
10
+ // digests and that this object still deep-equals the vendored bytes. Re-pin by first
11
+ // recording the commit/version in this script's PRODUCER_RELEASES map, then run:
11
12
  // node scripts/vendor-pi-daddy-contract.mjs <pi-daddy-checkout> <commit> [pr]
12
- /** pi-daddy commit whose contract artifact this schema was taken from. */
13
- export const PI_DADDY_CONTRACT_COMMIT = "1948b9406c13c9730f2fc103e68023d6e58c5e85";
13
+ /** pi-daddy commit whose contract artifacts this schema was taken from. */
14
+ export const PI_DADDY_CONTRACT_COMMIT = "c364a6717e3d5e369ecd3298b9cbb595eb94d9b2";
14
15
  /** SHA-256 of the byte-exact producer schema file this object was generated from. */
15
- export const PI_DADDY_LEDGER_V2_SCHEMA_SHA256 = "69c3a6856481b9250587c5785a8aadda87baba6cb03c79b209cff4f55f70a81c";
16
+ export const PI_DADDY_LEDGER_V2_SCHEMA_SHA256 = "3862bc451c25393dd40b198c62a8f94a3f58784e31da6dff05e3f06be71a3f86";
16
17
  /** pi-daddy's canonical, closed ledgerVersion 2 event schema (JSON Schema draft 2020-12). */
17
18
  export const PI_DADDY_LEDGER_V2_SCHEMA = {
18
19
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -151,6 +152,7 @@ export const PI_DADDY_LEDGER_V2_SCHEMA = {
151
152
  "LEDGER_WRITE_FAILED",
152
153
  "FANOUT_FAILED",
153
154
  "WORKSPACE_NOT_REGISTERED",
155
+ "WORKSPACE_NOT_AUTHORIZED",
154
156
  "WORKSPACE_WRITE_CONFLICT",
155
157
  "WORKSPACE_LEASE_STALE",
156
158
  "CHECK_NOT_CONFIGURED",