@kindgi/guardrails 0.0.0-bootstrap.0 → 0.1.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.
Files changed (55) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +78 -1
  3. package/dist/action-handler.d.ts +82 -0
  4. package/dist/action-handler.d.ts.map +1 -0
  5. package/dist/action-handler.js +120 -0
  6. package/dist/action-handler.js.map +1 -0
  7. package/dist/checks.d.ts +9 -0
  8. package/dist/checks.d.ts.map +1 -0
  9. package/dist/checks.js +235 -0
  10. package/dist/checks.js.map +1 -0
  11. package/dist/define-check.d.ts +93 -0
  12. package/dist/define-check.d.ts.map +1 -0
  13. package/dist/define-check.js +110 -0
  14. package/dist/define-check.js.map +1 -0
  15. package/dist/define.d.ts +27 -0
  16. package/dist/define.d.ts.map +1 -0
  17. package/dist/define.js +126 -0
  18. package/dist/define.js.map +1 -0
  19. package/dist/engine.d.ts +49 -0
  20. package/dist/engine.d.ts.map +1 -0
  21. package/dist/engine.js +198 -0
  22. package/dist/engine.js.map +1 -0
  23. package/dist/errors.d.ts +91 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +4 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/execution-strategy.d.ts +80 -0
  28. package/dist/execution-strategy.d.ts.map +1 -0
  29. package/dist/execution-strategy.js +96 -0
  30. package/dist/execution-strategy.js.map +1 -0
  31. package/dist/guardrail.schema.json +261 -0
  32. package/dist/index.d.ts +16 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +11 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/judge.d.ts +31 -0
  37. package/dist/judge.d.ts.map +1 -0
  38. package/dist/judge.js +171 -0
  39. package/dist/judge.js.map +1 -0
  40. package/dist/types.d.ts +407 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +11 -0
  43. package/dist/types.js.map +1 -0
  44. package/package.json +64 -4
  45. package/src/action-handler.ts +179 -0
  46. package/src/checks.ts +236 -0
  47. package/src/define-check.ts +207 -0
  48. package/src/define.ts +146 -0
  49. package/src/engine.ts +271 -0
  50. package/src/errors.ts +107 -0
  51. package/src/execution-strategy.ts +184 -0
  52. package/src/guardrail.schema.json +261 -0
  53. package/src/index.ts +79 -0
  54. package/src/judge.ts +221 -0
  55. package/src/types.ts +455 -0
package/dist/checks.js ADDED
@@ -0,0 +1,235 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * Built-in check library. Every entry is `kind: 'zero-llm'` — pure
5
+ * functions over the run trace, no external calls, deterministic. See
6
+ * `judge.ts` for LLM-judge evaluation.
7
+ *
8
+ * Adding a new built-in check: implement the function, add it to
9
+ * `BUILT_IN_CHECKS`, document its `config` schema in the JSDoc block.
10
+ */
11
+ /**
12
+ * `must-cite`: assistant output must include at least N matches of the
13
+ * citation pattern. Config:
14
+ * `{ minCitations?: number /* default 1 *\/, sourcePattern?: string /* regex *\/ }`
15
+ *
16
+ * Default `sourcePattern` matches `[<name>]`-style citations; override for
17
+ * verticals with different citation conventions.
18
+ */
19
+ const mustCite = async (config, trace) => {
20
+ const minCitations = typeof config.minCitations === 'number' ? config.minCitations : 1;
21
+ const sourcePattern = typeof config.sourcePattern === 'string' ? config.sourcePattern : '\\[[^\\]]+\\]';
22
+ if (trace.output === undefined || trace.output.length === 0) {
23
+ return { passed: false, reason: 'output empty; nothing to cite' };
24
+ }
25
+ const re = new RegExp(sourcePattern, 'g');
26
+ const matches = trace.output.match(re) ?? [];
27
+ if (matches.length >= minCitations) {
28
+ return { passed: true, attributes: { citationCount: matches.length } };
29
+ }
30
+ return {
31
+ passed: false,
32
+ reason: `expected >= ${minCitations} citations, found ${matches.length}`,
33
+ attributes: { citationCount: matches.length },
34
+ };
35
+ };
36
+ /**
37
+ * `never-call-tool`: fail if any of the listed tools were invoked.
38
+ * Config: `{ tools: string[] }` — tool ids or names to forbid.
39
+ */
40
+ const neverCallTool = async (config, trace) => {
41
+ // Accept both tool id / name strings and ToolRef objects
42
+ // ({ id, version }) — pack config authors may use either.
43
+ const rawTools = Array.isArray(config.tools) ? config.tools : [];
44
+ const forbidden = new Set();
45
+ for (const entry of rawTools) {
46
+ if (typeof entry === 'string') {
47
+ forbidden.add(entry);
48
+ }
49
+ else if (entry !== null &&
50
+ typeof entry === 'object' &&
51
+ 'id' in entry &&
52
+ typeof entry.id === 'string') {
53
+ forbidden.add(entry.id);
54
+ }
55
+ }
56
+ const violations = [];
57
+ for (const call of trace.toolCalls) {
58
+ if (forbidden.has(call.toolId) || forbidden.has(call.toolName)) {
59
+ violations.push(call.toolName);
60
+ }
61
+ }
62
+ if (violations.length === 0)
63
+ return { passed: true };
64
+ return {
65
+ passed: false,
66
+ reason: `forbidden tool(s) invoked: ${[...new Set(violations)].join(', ')}`,
67
+ attributes: { violatingTools: [...new Set(violations)] },
68
+ };
69
+ };
70
+ /**
71
+ * `max-tool-calls`: cap total tool invocations. Config: `{ max?: number }` (default 10).
72
+ * Guards against runaway agents.
73
+ */
74
+ const maxToolCalls = async (config, trace) => {
75
+ const max = typeof config.max === 'number' ? config.max : 10;
76
+ if (trace.toolCalls.length <= max) {
77
+ return { passed: true, attributes: { toolCallCount: trace.toolCalls.length } };
78
+ }
79
+ return {
80
+ passed: false,
81
+ reason: `expected <= ${max} tool calls, saw ${trace.toolCalls.length}`,
82
+ attributes: { toolCallCount: trace.toolCalls.length },
83
+ };
84
+ };
85
+ /**
86
+ * `output-matches`: final assistant output must match a regex (or fail
87
+ * if `negate: true`). Config: `{ pattern: string, flags?: string, negate?: boolean }`.
88
+ */
89
+ const outputMatches = async (config, trace) => {
90
+ const pattern = typeof config.pattern === 'string' ? config.pattern : '';
91
+ const flags = typeof config.flags === 'string' ? config.flags : '';
92
+ const negate = config.negate === true;
93
+ if (pattern.length === 0) {
94
+ return { passed: false, reason: 'pattern config is required' };
95
+ }
96
+ const re = new RegExp(pattern, flags);
97
+ const output = trace.output ?? '';
98
+ const matched = re.test(output);
99
+ const passed = negate ? !matched : matched;
100
+ return passed
101
+ ? { passed: true }
102
+ : {
103
+ passed: false,
104
+ reason: negate
105
+ ? `output matched forbidden pattern /${pattern}/`
106
+ : `output did not match /${pattern}/`,
107
+ };
108
+ };
109
+ /**
110
+ * `tool-order`: tool calls must appear in a specified order. Config:
111
+ * `{ sequence: string[] }` — tool names in expected order (subsequence).
112
+ * Non-listed tools are allowed to appear anywhere; the sequence must exist
113
+ * as a subsequence of the actual call order.
114
+ */
115
+ const toolOrder = async (config, trace) => {
116
+ const sequence = Array.isArray(config.sequence) ? config.sequence : [];
117
+ if (sequence.length === 0)
118
+ return { passed: true };
119
+ let seqIndex = 0;
120
+ for (const call of trace.toolCalls) {
121
+ if (call.toolName === sequence[seqIndex])
122
+ seqIndex += 1;
123
+ if (seqIndex === sequence.length)
124
+ return { passed: true };
125
+ }
126
+ return {
127
+ passed: false,
128
+ reason: `expected tool-call subsequence [${sequence.join(', ')}] not observed`,
129
+ attributes: { matchedPrefix: sequence.slice(0, seqIndex) },
130
+ };
131
+ };
132
+ /**
133
+ * `required-substring`: `trace.output` must contain EVERY listed pattern.
134
+ * Config: `{ patterns: string[], caseSensitive?: boolean }`.
135
+ *
136
+ * Mirror of `forbidden-substring` — enables "output must include the
137
+ * standard legal disclaimer / required attribution / policy footer"
138
+ * without needing an llm-judge.
139
+ *
140
+ * Empty `patterns` array passes vacuously. Missing `output` on the
141
+ * trace fails (nothing can contain the required text).
142
+ */
143
+ const requiredSubstring = async (config, trace) => {
144
+ const patternsRaw = Array.isArray(config.patterns) ? config.patterns : [];
145
+ const patterns = patternsRaw.filter((p) => typeof p === 'string' && p.length > 0);
146
+ if (patterns.length === 0)
147
+ return { passed: true };
148
+ if (trace.output === undefined || trace.output.length === 0) {
149
+ return {
150
+ passed: false,
151
+ reason: `output empty; ${patterns.length} required pattern(s) not satisfied`,
152
+ attributes: { missing: patterns },
153
+ };
154
+ }
155
+ const caseSensitive = config.caseSensitive === true;
156
+ const haystack = caseSensitive ? trace.output : trace.output.toLowerCase();
157
+ const missing = [];
158
+ for (const p of patterns) {
159
+ const needle = caseSensitive ? p : p.toLowerCase();
160
+ if (!haystack.includes(needle))
161
+ missing.push(p);
162
+ }
163
+ if (missing.length === 0)
164
+ return { passed: true };
165
+ return {
166
+ passed: false,
167
+ reason: `output missing required pattern(s): ${missing.join(', ')}`,
168
+ attributes: { missing },
169
+ };
170
+ };
171
+ /**
172
+ * `forbidden-substring`: `trace.output` must NOT contain any listed pattern.
173
+ * Config: `{ patterns: string[], caseSensitive?: boolean }`.
174
+ *
175
+ * Symmetric to `required-substring`. Enables "output must not contain
176
+ * PII markers / off-limits phrases / policy trigger words" without an
177
+ * llm-judge.
178
+ */
179
+ const forbiddenSubstring = async (config, trace) => {
180
+ const patternsRaw = Array.isArray(config.patterns) ? config.patterns : [];
181
+ const patterns = patternsRaw.filter((p) => typeof p === 'string' && p.length > 0);
182
+ if (patterns.length === 0)
183
+ return { passed: true };
184
+ if (trace.output === undefined || trace.output.length === 0)
185
+ return { passed: true };
186
+ const caseSensitive = config.caseSensitive === true;
187
+ const haystack = caseSensitive ? trace.output : trace.output.toLowerCase();
188
+ const violated = [];
189
+ for (const p of patterns) {
190
+ const needle = caseSensitive ? p : p.toLowerCase();
191
+ if (haystack.includes(needle))
192
+ violated.push(p);
193
+ }
194
+ if (violated.length === 0)
195
+ return { passed: true };
196
+ return {
197
+ passed: false,
198
+ reason: `output contains forbidden pattern(s): ${violated.join(', ')}`,
199
+ attributes: { violated },
200
+ };
201
+ };
202
+ const BUILT_IN_CHECKS = [
203
+ { id: 'must-cite', kind: 'zero-llm', evaluate: mustCite },
204
+ { id: 'never-call-tool', kind: 'zero-llm', evaluate: neverCallTool },
205
+ { id: 'max-tool-calls', kind: 'zero-llm', evaluate: maxToolCalls },
206
+ { id: 'output-matches', kind: 'zero-llm', evaluate: outputMatches },
207
+ { id: 'tool-order', kind: 'zero-llm', evaluate: toolOrder },
208
+ { id: 'required-substring', kind: 'zero-llm', evaluate: requiredSubstring },
209
+ { id: 'forbidden-substring', kind: 'zero-llm', evaluate: forbiddenSubstring },
210
+ ];
211
+ /**
212
+ * Create a fresh CheckRegistry pre-populated with built-in checks.
213
+ * Consumers register custom checks at pack init.
214
+ */
215
+ export function createCheckRegistry(seed = []) {
216
+ const checks = new Map();
217
+ for (const c of BUILT_IN_CHECKS)
218
+ checks.set(c.id, c);
219
+ for (const c of seed)
220
+ checks.set(c.id, c);
221
+ return {
222
+ register(check) {
223
+ checks.set(check.id, check);
224
+ },
225
+ get(id) {
226
+ return checks.get(id);
227
+ },
228
+ list() {
229
+ return [...checks.values()];
230
+ },
231
+ };
232
+ }
233
+ /** Exported for tests + downstream introspection. */
234
+ export const BUILT_IN_CHECK_IDS = BUILT_IN_CHECKS.map((c) => c.id);
235
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import type { AnySchema, ZodLikeSchema } from '@kindgi/schema';
2
+ import type { CheckFunction, GuardrailKind, RegisteredCheck } from './types.js';
3
+ /**
4
+ * Author-time inference from a Zod schema's `_zod.output`. Non-Zod
5
+ * schemas fall through to `Readonly<Record<string, unknown>>` — the
6
+ * same type that `Guardrail.config` already carries.
7
+ */
8
+ export type InferCheckConfig<T> = T extends {
9
+ readonly _zod: {
10
+ readonly output: infer O;
11
+ };
12
+ } ? O : Readonly<Record<string, unknown>>;
13
+ /**
14
+ * The author-facing spec accepted by `defineCheck`. Extends
15
+ * `RegisteredCheck` with an optional `configSchema` slot that can be
16
+ * either a JSON Schema object or a Zod v4 schema. When set,
17
+ * `defineCheck` derives `validateConfig` from the schema — authors
18
+ * don't have to write it separately.
19
+ *
20
+ * `evaluate` is typed against the schema-inferred config for Zod-
21
+ * authored checks; JSON-Schema-authored checks fall back to
22
+ * `Readonly<Record<string, unknown>>`.
23
+ */
24
+ export interface DefineCheckSpec<TConfigSchema extends AnySchema> {
25
+ /**
26
+ * Check identifier. Referenced by `Guardrail.check` on the wire.
27
+ * Convention: dot-namespaced for pack-authored checks (e.g.
28
+ * `'acme.max-citations'`); framework-shipped checks use stable ids
29
+ * like `'must-cite'` / `'never-call-tool'`.
30
+ */
31
+ readonly id: string;
32
+ /**
33
+ * `'zero-llm'` — pure function over the trace (fast, deterministic,
34
+ * default). `'llm-judge'` — uses a model (opt-in, costs money;
35
+ * needs `bindings.providerRegistry` or `bindings.judgeProvider`).
36
+ * `'external'` — evaluated by a caller-registered strategy.
37
+ */
38
+ readonly kind: GuardrailKind;
39
+ /**
40
+ * Config schema — Zod v4 or JSON Schema. When present, `defineCheck`
41
+ * derives `RegisteredCheck.validateConfig` from it, and
42
+ * `defineGuardrail` runs that against each `Guardrail.config`.
43
+ * Zod authors get schema-inferred config types on `evaluate`'s first
44
+ * parameter.
45
+ */
46
+ readonly configSchema?: TConfigSchema;
47
+ /**
48
+ * The check function. Signature: `(config, trace, bindings) => Promise<CheckResult>`.
49
+ * `config` is the guardrail's declared config (typed via `configSchema`
50
+ * when Zod-authored). `trace` is the accumulated `RunTrace` from the
51
+ * agent turn. `bindings` is the `EvaluationBindings` the caller
52
+ * passed to the engine (`{}` when none).
53
+ * Return `{passed: true}` or `{passed: false, reason: string, ...}`.
54
+ */
55
+ readonly evaluate: (config: InferCheckConfig<TConfigSchema>, trace: Parameters<CheckFunction>[1], bindings: Parameters<CheckFunction>[2]) => ReturnType<CheckFunction>;
56
+ /**
57
+ * Optional custom config validator. When `configSchema` is also set,
58
+ * both run — `configSchema` first, then this. `undefined` return means
59
+ * "config is valid"; non-undefined string is the error message.
60
+ */
61
+ readonly validateConfig?: (config: unknown) => string | undefined;
62
+ }
63
+ /**
64
+ * The concrete RegisteredCheck returned by `defineCheck`. When the
65
+ * author provided a Zod schema at `configSchema`, `configZod` is
66
+ * present so TS callers can `z.infer<typeof check.configZod>` for
67
+ * static types.
68
+ */
69
+ export type DefinedCheck<TConfigSchema extends AnySchema> = RegisteredCheck & {
70
+ readonly configZod: TConfigSchema extends ZodLikeSchema ? TConfigSchema : undefined;
71
+ readonly configJsonSchema?: Readonly<Record<string, unknown>>;
72
+ };
73
+ /**
74
+ * Build a `RegisteredCheck` with optional schema-derived config
75
+ * validation. Two authoring surfaces coexist:
76
+ * 1. JSON Schema Draft 2020-12 objects — compiled at author time
77
+ * via Ajv; the check's `validateConfig` is derived from the
78
+ * compiled validator.
79
+ * 2. Zod v4 schemas — converted via `z.toJSONSchema()` (peer dep),
80
+ * then compiled the same way. TS callers get `z.infer<typeof
81
+ * check.configZod>` for static config typing.
82
+ *
83
+ * When `configSchema` is omitted, this behaves as a passthrough:
84
+ * returns the check with the caller's `validateConfig` (or undefined).
85
+ *
86
+ * Failures at author time (Zod conversion or Ajv compile) surface via
87
+ * throw — same failure mode as construction of a bad
88
+ * `RegisteredCheck` object literal. Consumers catch at pack-init;
89
+ * downstream `defineGuardrail` runs the derived `validateConfig` at
90
+ * spec-registration time and reports via `Result`.
91
+ */
92
+ export declare function defineCheck<TConfigSchema extends AnySchema = AnySchema>(spec: DefineCheckSpec<TConfigSchema>): DefinedCheck<TConfigSchema>;
93
+ //# sourceMappingURL=define-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-check.d.ts","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAShF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAAE,GACvF,CAAC,GACD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe,CAAC,aAAa,SAAS,SAAS;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC;IACtC;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,MAAM,EAAE,gBAAgB,CAAC,aAAa,CAAC,EACvC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EACnC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KACnC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;CACnE;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,CAAC,aAAa,SAAS,SAAS,IAAI,eAAe,GAAG;IAC5E,QAAQ,CAAC,SAAS,EAAE,aAAa,SAAS,aAAa,GAAG,aAAa,GAAG,SAAS,CAAC;IACpF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,aAAa,SAAS,SAAS,GAAG,SAAS,EACrE,IAAI,EAAE,eAAe,CAAC,aAAa,CAAC,GACnC,YAAY,CAAC,aAAa,CAAC,CAiE7B"}
@@ -0,0 +1,110 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ import * as addFormatsModule from 'ajv-formats';
4
+ import { Ajv2020 } from 'ajv/dist/2020.js';
5
+ import { isZodSchema, loadZodConverterSync, toJSONSchemaSync } from '@kindgi/schema';
6
+ const addFormatsRaw = addFormatsModule;
7
+ const addFormats = typeof addFormatsRaw === 'function'
8
+ ? addFormatsRaw
9
+ : addFormatsRaw.default;
10
+ /**
11
+ * Build a `RegisteredCheck` with optional schema-derived config
12
+ * validation. Two authoring surfaces coexist:
13
+ * 1. JSON Schema Draft 2020-12 objects — compiled at author time
14
+ * via Ajv; the check's `validateConfig` is derived from the
15
+ * compiled validator.
16
+ * 2. Zod v4 schemas — converted via `z.toJSONSchema()` (peer dep),
17
+ * then compiled the same way. TS callers get `z.infer<typeof
18
+ * check.configZod>` for static config typing.
19
+ *
20
+ * When `configSchema` is omitted, this behaves as a passthrough:
21
+ * returns the check with the caller's `validateConfig` (or undefined).
22
+ *
23
+ * Failures at author time (Zod conversion or Ajv compile) surface via
24
+ * throw — same failure mode as construction of a bad
25
+ * `RegisteredCheck` object literal. Consumers catch at pack-init;
26
+ * downstream `defineGuardrail` runs the derived `validateConfig` at
27
+ * spec-registration time and reports via `Result`.
28
+ */
29
+ export function defineCheck(spec) {
30
+ const converter = spec.configSchema !== undefined && isZodSchema(spec.configSchema)
31
+ ? loadZodConverterSync()
32
+ : undefined;
33
+ let derivedValidator;
34
+ let jsonSchema;
35
+ let zodSchema;
36
+ if (spec.configSchema !== undefined) {
37
+ if (isZodSchema(spec.configSchema)) {
38
+ zodSchema = spec.configSchema;
39
+ const converted = toJSONSchemaSync(spec.configSchema, converter, 'input');
40
+ if (converted.kind === 'err') {
41
+ const err = {
42
+ code: 'invalid-check-definition',
43
+ message: `Check "${spec.id}" configSchema Zod conversion failed: ${converted.error.message}`,
44
+ checkId: spec.id,
45
+ cause: converted.error.cause,
46
+ };
47
+ throw errorFromDefinition(err);
48
+ }
49
+ jsonSchema = converted.value;
50
+ }
51
+ else {
52
+ jsonSchema = spec.configSchema;
53
+ }
54
+ const validator = compileValidator(jsonSchema, spec.id);
55
+ derivedValidator = (config) => {
56
+ if (!validator(config)) {
57
+ const errors = validator.errors ?? [];
58
+ const first = errors[0];
59
+ const path = first?.instancePath ?? '';
60
+ const message = first?.message ?? 'invalid config';
61
+ return `${path} ${message}`.trim();
62
+ }
63
+ return undefined;
64
+ };
65
+ }
66
+ const chainValidator = (a, b) => {
67
+ if (a === undefined)
68
+ return b;
69
+ if (b === undefined)
70
+ return a;
71
+ return (config) => {
72
+ const first = a(config);
73
+ if (first !== undefined)
74
+ return first;
75
+ return b(config);
76
+ };
77
+ };
78
+ const validate = chainValidator(derivedValidator, spec.validateConfig);
79
+ const check = {
80
+ id: spec.id,
81
+ kind: spec.kind,
82
+ evaluate: spec.evaluate,
83
+ ...(validate !== undefined && { validateConfig: validate }),
84
+ ...(zodSchema !== undefined && { configZod: zodSchema }),
85
+ ...(jsonSchema !== undefined && { configJsonSchema: jsonSchema }),
86
+ };
87
+ return check;
88
+ }
89
+ function compileValidator(schema, checkId) {
90
+ const ajv = new Ajv2020({ strict: true, allErrors: true, allowUnionTypes: false });
91
+ addFormats(ajv);
92
+ try {
93
+ return ajv.compile(schema);
94
+ }
95
+ catch (cause) {
96
+ const err = {
97
+ code: 'invalid-check-definition',
98
+ message: `Check "${checkId}" configSchema does not compile as JSON Schema Draft 2020-12: ${cause instanceof Error ? cause.message : String(cause)}`,
99
+ checkId,
100
+ cause,
101
+ };
102
+ throw errorFromDefinition(err);
103
+ }
104
+ }
105
+ function errorFromDefinition(err) {
106
+ const wrapped = new Error(err.message);
107
+ Object.assign(wrapped, err);
108
+ return wrapped;
109
+ }
110
+ //# sourceMappingURL=define-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-check.js","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { Result } from '@kindgi/types';
2
+ import type { InvalidCheckConfigError, InvalidGuardrailError, UnknownCheckError } from './errors.js';
3
+ import type { CheckRegistry, Guardrail } from './types.js';
4
+ /**
5
+ * Validate a guardrail declaration + resolve its check.
6
+ *
7
+ * Fails if:
8
+ * 1. The declaration doesn't match `@kindgi/specs/guardrail.schema.json`.
9
+ * 2. The `check` id isn't in the registry.
10
+ * 3. The registered check's `kind` differs from the guardrail's `kind`.
11
+ * 4. The check has a config validator and `guardrail.config` fails it.
12
+ *
13
+ * Every failure surfaces at pack-init — before any run touches the guardrail.
14
+ */
15
+ export declare function defineGuardrail(spec: Guardrail, checks: CheckRegistry): Result<Guardrail, InvalidGuardrailError | UnknownCheckError | InvalidCheckConfigError>;
16
+ /**
17
+ * Validate an arbitrary wire spec against `@kindgi/specs/guardrail.schema.json`.
18
+ * Unlike `defineGuardrail`, this does NOT resolve the `check` reference
19
+ * against a `CheckRegistry` — used by transport layers (e.g. the
20
+ * `@kindgi/api` guardrail routes) that accept metadata-only guardrail
21
+ * registrations. The check implementation must already be available to
22
+ * the server that evaluates the guardrail.
23
+ */
24
+ export declare function validateGuardrailSpec(spec: unknown): Result<Guardrail, InvalidGuardrailError>;
25
+ /** The `$id` of the JSON Schema this loader validates against. */
26
+ export declare const GUARDRAIL_SCHEMA_URI = "https://kindgi.com/schemas/v1/guardrail.schema.json";
27
+ //# sourceMappingURL=define.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAe3D;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,aAAa,GACpB,MAAM,CAAC,SAAS,EAAE,qBAAqB,GAAG,iBAAiB,GAAG,uBAAuB,CAAC,CA4DxF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,SAAS,EAAE,qBAAqB,CAAC,CA8B7F;AAED,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,wDAAsB,CAAC"}
package/dist/define.js ADDED
@@ -0,0 +1,126 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ import { createSpecRegistry } from '@kindgi/schema';
4
+ import guardrailSchema from './guardrail.schema.json' with { type: 'json' };
5
+ const GUARDRAIL_SCHEMA_ID = 'https://kindgi.com/schemas/v1/guardrail.schema.json';
6
+ let cachedRegistry;
7
+ function schemaRegistry() {
8
+ if (cachedRegistry !== undefined)
9
+ return cachedRegistry;
10
+ const built = createSpecRegistry([guardrailSchema]);
11
+ if (built.kind === 'err') {
12
+ throw new Error(`@kindgi/guardrails: bundled schema failed to compile: ${built.error.message}`);
13
+ }
14
+ cachedRegistry = built.value;
15
+ return cachedRegistry;
16
+ }
17
+ /**
18
+ * Validate a guardrail declaration + resolve its check.
19
+ *
20
+ * Fails if:
21
+ * 1. The declaration doesn't match `@kindgi/specs/guardrail.schema.json`.
22
+ * 2. The `check` id isn't in the registry.
23
+ * 3. The registered check's `kind` differs from the guardrail's `kind`.
24
+ * 4. The check has a config validator and `guardrail.config` fails it.
25
+ *
26
+ * Every failure surfaces at pack-init — before any run touches the guardrail.
27
+ */
28
+ export function defineGuardrail(spec, checks) {
29
+ const r = schemaRegistry().validate(GUARDRAIL_SCHEMA_ID, spec);
30
+ if (r.kind === 'err') {
31
+ const err = r.error;
32
+ if (err.code !== 'validation-error') {
33
+ throw new Error(`@kindgi/guardrails: unexpected schema error ${err.code}: ${err.message}`);
34
+ }
35
+ const issues = err.errors.map((e) => {
36
+ const ajv = e;
37
+ return {
38
+ path: typeof ajv.instancePath === 'string' ? ajv.instancePath : '',
39
+ message: typeof ajv.message === 'string' ? ajv.message : 'validation failed',
40
+ };
41
+ });
42
+ return {
43
+ kind: 'err',
44
+ error: { code: 'invalid-guardrail', message: err.message, issues },
45
+ };
46
+ }
47
+ const check = checks.get(spec.check);
48
+ if (check === undefined) {
49
+ return {
50
+ kind: 'err',
51
+ error: {
52
+ code: 'unknown-check',
53
+ message: `Guardrail "${spec.id}" references unregistered check "${spec.check}"`,
54
+ guardrailId: spec.id,
55
+ checkId: spec.check,
56
+ },
57
+ };
58
+ }
59
+ if (check.kind !== spec.kind) {
60
+ return {
61
+ kind: 'err',
62
+ error: {
63
+ code: 'invalid-guardrail',
64
+ message: `Guardrail "${spec.id}" kind "${spec.kind}" does not match check "${spec.check}" kind "${check.kind}"`,
65
+ issues: [{ path: '/kind', message: `expected "${check.kind}"` }],
66
+ },
67
+ };
68
+ }
69
+ if (check.validateConfig !== undefined && spec.config !== undefined) {
70
+ const reason = check.validateConfig(spec.config);
71
+ if (reason !== undefined) {
72
+ return {
73
+ kind: 'err',
74
+ error: {
75
+ code: 'invalid-check-config',
76
+ message: `Guardrail "${spec.id}" config invalid: ${reason}`,
77
+ guardrailId: spec.id,
78
+ reason,
79
+ },
80
+ };
81
+ }
82
+ }
83
+ return { kind: 'ok', value: spec };
84
+ }
85
+ /**
86
+ * Validate an arbitrary wire spec against `@kindgi/specs/guardrail.schema.json`.
87
+ * Unlike `defineGuardrail`, this does NOT resolve the `check` reference
88
+ * against a `CheckRegistry` — used by transport layers (e.g. the
89
+ * `@kindgi/api` guardrail routes) that accept metadata-only guardrail
90
+ * registrations. The check implementation must already be available to
91
+ * the server that evaluates the guardrail.
92
+ */
93
+ export function validateGuardrailSpec(spec) {
94
+ if (spec === null || typeof spec !== 'object') {
95
+ return {
96
+ kind: 'err',
97
+ error: {
98
+ code: 'invalid-guardrail',
99
+ message: 'Guardrail spec must be an object',
100
+ issues: [{ path: '', message: 'must be an object' }],
101
+ },
102
+ };
103
+ }
104
+ const r = schemaRegistry().validate(GUARDRAIL_SCHEMA_ID, spec);
105
+ if (r.kind === 'err') {
106
+ const err = r.error;
107
+ if (err.code !== 'validation-error') {
108
+ throw new Error(`@kindgi/guardrails: unexpected schema error ${err.code}: ${err.message}`);
109
+ }
110
+ const issues = err.errors.map((e) => {
111
+ const ajv = e;
112
+ return {
113
+ path: typeof ajv.instancePath === 'string' ? ajv.instancePath : '',
114
+ message: typeof ajv.message === 'string' ? ajv.message : 'validation failed',
115
+ };
116
+ });
117
+ return {
118
+ kind: 'err',
119
+ error: { code: 'invalid-guardrail', message: err.message, issues },
120
+ };
121
+ }
122
+ return { kind: 'ok', value: spec };
123
+ }
124
+ /** The `$id` of the JSON Schema this loader validates against. */
125
+ export const GUARDRAIL_SCHEMA_URI = GUARDRAIL_SCHEMA_ID;
126
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}