structured-context 0.19.0 → 0.21.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/dist/api.d.ts +2 -1
- package/dist/api.js +2 -1
- package/dist/commands/validate-file.d.ts +2 -4
- package/dist/commands/validate-file.js +1 -8
- package/dist/commands/validate.d.ts +2 -5
- package/dist/commands/validate.js +1 -8
- package/dist/errors.d.ts +1 -1
- package/dist/index.js +6 -28
- package/dist/judge/factory.d.ts +1 -3
- package/dist/judge/factory.js +7 -8
- package/dist/space-context.d.ts +2 -8
- package/dist/space-context.js +3 -13
- package/dist/validate.d.ts +48 -13
- package/dist/validate.js +20 -12
- package/package.json +1 -1
- package/dist/judge/index.d.ts +0 -13
- package/dist/judge/index.js +0 -8
package/dist/api.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type { Config, SpaceConfig } from './config';
|
|
|
23
23
|
export { loadConfig, resolveConfigPath, resolveSchema, resolveSchemaPath, setConfigPath } from './config';
|
|
24
24
|
export { addSpace } from './config/write';
|
|
25
25
|
export { LOCAL_CONFIG_FILE, PLUGIN_PREFIX } from './constants';
|
|
26
|
+
export { SctxError, type SctxErrorCode } from './errors';
|
|
26
27
|
export { assembleSpaceGraph, loadSpaceGraph } from './load-space-graph';
|
|
27
28
|
export type { ParseHook, ParseResult, PluginContext, RenderFileOutput, RenderFormat, RenderHook, RenderMultiFileOutput, RenderOptions, RenderResult, StructuredContextPlugin, TemplateSyncHook, TemplateSyncOptions, } from './plugins/util';
|
|
28
29
|
export { isRenderMultiFileOutput, resolvePluginDir, resolvePluginSchemasDir, resolveSpacePluginSchemas, } from './plugins/util';
|
|
@@ -31,7 +32,7 @@ export { buildTargetIndex, formatWikilink, type ParsedWikilink, parseWikilink, w
|
|
|
31
32
|
export { listSchemas } from './schema/list-schemas';
|
|
32
33
|
export type { SharedEmbeddingFields } from './schema/metadata-contract';
|
|
33
34
|
export { bundledSchemasDir, loadSchema, type PluginSchemaSource, setBundledSchemasDir } from './schema/schema';
|
|
34
|
-
export { createSpaceContext
|
|
35
|
+
export { createSpaceContext } from './space-context';
|
|
35
36
|
export { buildSpaceGraph } from './space-graph';
|
|
36
37
|
export { exportSpaceGraph } from './space-graph-data';
|
|
37
38
|
export type { BaseNode, ContentLink, EdgeDefinition, FileNotInSpaceResult, FileValidationIssue, FileValidationResult, Hierarchy, HierarchyLevel, ParseIssue, ReadSpaceResult, Relationship, ResolvedContentLink, RuleCategory, RuleSeverity, RuleViolation, SchemaMetadata, SchemaWithMetadata, SourceLocation, SpaceContext, UnresolvedRef, ValidateFileOutput, } from './types';
|
package/dist/api.js
CHANGED
|
@@ -22,13 +22,14 @@ export { spaceGraphFrom } from './browser';
|
|
|
22
22
|
export { loadConfig, resolveConfigPath, resolveSchema, resolveSchemaPath, setConfigPath } from './config';
|
|
23
23
|
export { addSpace } from './config/write';
|
|
24
24
|
export { LOCAL_CONFIG_FILE, PLUGIN_PREFIX } from './constants';
|
|
25
|
+
export { SctxError } from './errors';
|
|
25
26
|
export { assembleSpaceGraph, loadSpaceGraph } from './load-space-graph';
|
|
26
27
|
export { isRenderMultiFileOutput, resolvePluginDir, resolvePluginSchemasDir, resolveSpacePluginSchemas, } from './plugins/util';
|
|
27
28
|
export { readSpace } from './read/read-space';
|
|
28
29
|
export { buildTargetIndex, formatWikilink, parseWikilink, wikilinkToTarget, } from './read/wikilink-utils';
|
|
29
30
|
export { listSchemas } from './schema/list-schemas';
|
|
30
31
|
export { bundledSchemasDir, loadSchema, setBundledSchemasDir } from './schema/schema';
|
|
31
|
-
export { createSpaceContext
|
|
32
|
+
export { createSpaceContext } from './space-context';
|
|
32
33
|
export { buildSpaceGraph } from './space-graph';
|
|
33
34
|
export { exportSpaceGraph } from './space-graph-data';
|
|
34
35
|
export { validateFile, validateSpace } from './validate';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ValidateFileOptions } from '../validate';
|
|
1
2
|
export { validateFile } from '../validate';
|
|
2
3
|
/**
|
|
3
4
|
* CLI command: validate a file and print results to stdout.
|
|
@@ -6,7 +7,4 @@ export { validateFile } from '../validate';
|
|
|
6
7
|
*/
|
|
7
8
|
export declare function validateFileCommand(filePath: string, options?: {
|
|
8
9
|
json?: boolean;
|
|
9
|
-
|
|
10
|
-
semantic?: boolean | string;
|
|
11
|
-
ruleFilter?: string[];
|
|
12
|
-
}): Promise<number>;
|
|
10
|
+
} & Omit<ValidateFileOptions, 'configDir'>): Promise<number>;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { loadConfig } from '../config';
|
|
2
|
-
import { judgeForRun } from '../judge/factory';
|
|
3
|
-
import { parseRuleFilter } from '../schema/rule-filter';
|
|
4
2
|
import { createSpaceContext } from '../space-context';
|
|
5
3
|
import { fileNotInSpace, resolveFileSpace, validateResolvedFile } from '../validate';
|
|
6
4
|
export { validateFile } from '../validate';
|
|
@@ -14,12 +12,7 @@ export async function validateFileCommand(filePath, options = {}) {
|
|
|
14
12
|
const resolved = resolveFileSpace(filePath, config);
|
|
15
13
|
let result;
|
|
16
14
|
if (resolved) {
|
|
17
|
-
|
|
18
|
-
result = await validateResolvedFile(filePath, resolved.label, createSpaceContext(resolved.space.name, config), {
|
|
19
|
-
includeGated: options.includeGated,
|
|
20
|
-
judge,
|
|
21
|
-
ruleFilter: options.ruleFilter && parseRuleFilter(options.ruleFilter),
|
|
22
|
-
});
|
|
15
|
+
result = await validateResolvedFile(filePath, resolved.label, createSpaceContext(resolved.space.name, config), options);
|
|
23
16
|
}
|
|
24
17
|
else {
|
|
25
18
|
result = fileNotInSpace(filePath);
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { SpaceContext } from '../types';
|
|
2
|
+
import { type ValidateSpaceOptions } from '../validate';
|
|
2
3
|
export declare function validate(context: SpaceContext, options?: {
|
|
3
4
|
json?: boolean;
|
|
4
|
-
|
|
5
|
-
includeGated?: boolean;
|
|
6
|
-
semantic?: boolean | string;
|
|
7
|
-
ruleFilter?: string[];
|
|
8
|
-
}): Promise<number>;
|
|
5
|
+
} & ValidateSpaceOptions): Promise<number>;
|
|
9
6
|
export declare function watchValidate(context: SpaceContext): Promise<never>;
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { dirname } from 'node:path';
|
|
2
2
|
import chokidar from 'chokidar';
|
|
3
3
|
import { getConfigSourceFiles } from '../config';
|
|
4
|
-
import { judgeForRun } from '../judge/factory';
|
|
5
4
|
import { resolveSpacePluginSchemas } from '../plugins/util';
|
|
6
|
-
import { parseRuleFilter } from '../schema/rule-filter';
|
|
7
5
|
import { bundledSchemasDir } from '../schema/schema';
|
|
8
6
|
import { formatSource, ruleViolationMessage, validateSpace } from '../validate';
|
|
9
7
|
export async function validate(context, options = {}) {
|
|
10
|
-
const result = await validateSpace(context,
|
|
11
|
-
depth: options.depth,
|
|
12
|
-
includeGated: options.includeGated,
|
|
13
|
-
judge: judgeForRun(context.config, context.space, options.semantic),
|
|
14
|
-
ruleFilter: options.ruleFilter && parseRuleFilter(options.ruleFilter),
|
|
15
|
-
});
|
|
8
|
+
const result = await validateSpace(context, options);
|
|
16
9
|
const ruleCounts = { error: 0, warning: 0, info: 0 };
|
|
17
10
|
for (const v of result.ruleViolations)
|
|
18
11
|
ruleCounts[v.severity]++;
|
package/dist/errors.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Stable codes for configuration and environment problems. Hooks and agent skills map a code to a
|
|
3
3
|
* fix, so the message wording can change without breaking them.
|
|
4
4
|
*/
|
|
5
|
-
export type SctxErrorCode = 'E_CONFIG_NOT_FOUND' | 'E_CONFIG_INVALID' | 'E_INCLUDE_NOT_FOUND' | 'E_NO_SPACES' | 'E_SPACE_PATH_MISSING' | 'E_SCHEMA_MISSING' | 'E_SCHEMA_NOT_FOUND' | 'E_SCHEMA_INVALID' | 'E_SPACE_EXISTS' | 'E_TARGET_REQUIRED' | 'E_CONFIG_NEEDS_MANUAL_EDIT';
|
|
5
|
+
export type SctxErrorCode = 'E_CONFIG_NOT_FOUND' | 'E_CONFIG_INVALID' | 'E_INCLUDE_NOT_FOUND' | 'E_NO_SPACES' | 'E_SPACE_PATH_MISSING' | 'E_SCHEMA_MISSING' | 'E_SCHEMA_NOT_FOUND' | 'E_SCHEMA_INVALID' | 'E_SPACE_EXISTS' | 'E_SPACE_NOT_FOUND' | 'E_TARGET_REQUIRED' | 'E_CONFIG_NEEDS_MANUAL_EDIT' | 'E_MODEL_PROVIDER_INVALID';
|
|
6
6
|
export declare class SctxError extends Error {
|
|
7
7
|
readonly code: SctxErrorCode;
|
|
8
8
|
constructor(code: SctxErrorCode, message: string);
|
package/dist/index.js
CHANGED
|
@@ -17,36 +17,14 @@ import { validateFileCommand } from './commands/validate-file';
|
|
|
17
17
|
import { loadConfig, setConfigPath } from './config';
|
|
18
18
|
import { CLI_NAME } from './constants';
|
|
19
19
|
import { SctxError } from './errors';
|
|
20
|
-
import {
|
|
21
|
-
import { createSpaceContext, SpaceNotFoundError } from './space-context';
|
|
20
|
+
import { createSpaceContext } from './space-context';
|
|
22
21
|
// Once node:process is loaded (vfile, via unified, loads it), Bun's console.log drops piped output
|
|
23
22
|
// past 64KB when the reader is slow. process.stdout.write delivers all of it before exit.
|
|
24
23
|
console.log = (...args) => {
|
|
25
24
|
process.stdout.write(`${format(...args)}\n`);
|
|
26
25
|
};
|
|
27
26
|
export function buildSpaceContext(spaceName) {
|
|
28
|
-
|
|
29
|
-
return createSpaceContext(spaceName, loadConfig());
|
|
30
|
-
}
|
|
31
|
-
catch (err) {
|
|
32
|
-
if (err instanceof SpaceNotFoundError) {
|
|
33
|
-
console.error(`Error: ${err.message}`);
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
throw err;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/** Run a validate command, reporting a misconfigured model provider as a plain error rather than a stack trace. */
|
|
40
|
-
async function reportJudgeConfigErrors(run) {
|
|
41
|
-
try {
|
|
42
|
-
return await run();
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
if (!(err instanceof JudgeConfigError))
|
|
46
|
-
throw err;
|
|
47
|
-
console.error(`Error: ${err.message}`);
|
|
48
|
-
return 1;
|
|
49
|
-
}
|
|
27
|
+
return createSpaceContext(spaceName, loadConfig());
|
|
50
28
|
}
|
|
51
29
|
const require = createRequire(import.meta.url);
|
|
52
30
|
const packageJson = require('../package.json');
|
|
@@ -68,12 +46,12 @@ program
|
|
|
68
46
|
.option('--rule-filter <dimension=values>', 'Evaluate only matching rules; dimensions: category, severity, type, id (repeatable, e.g. severity=error)', (v, prev = []) => [...prev, v])
|
|
69
47
|
.option('--semantic [provider]', 'Evaluate semantic rules, with the configured model provider or the one named')
|
|
70
48
|
.action(async (filePath, options) => {
|
|
71
|
-
process.exitCode = await
|
|
49
|
+
process.exitCode = await validateFileCommand(filePath, {
|
|
72
50
|
json: options.json,
|
|
73
51
|
includeGated: options.includeGated,
|
|
74
52
|
semantic: options.semantic,
|
|
75
53
|
ruleFilter: options.ruleFilter,
|
|
76
|
-
})
|
|
54
|
+
});
|
|
77
55
|
});
|
|
78
56
|
program
|
|
79
57
|
.command('validate')
|
|
@@ -92,13 +70,13 @@ program
|
|
|
92
70
|
}
|
|
93
71
|
else {
|
|
94
72
|
// exitCode rather than process.exit(): exiting straight away can cut off large piped output
|
|
95
|
-
process.exitCode = await
|
|
73
|
+
process.exitCode = await validate(context, {
|
|
96
74
|
json: options.json,
|
|
97
75
|
depth: options.depth,
|
|
98
76
|
includeGated: options.includeGated,
|
|
99
77
|
semantic: options.semantic,
|
|
100
78
|
ruleFilter: options.ruleFilter,
|
|
101
|
-
})
|
|
79
|
+
});
|
|
102
80
|
}
|
|
103
81
|
});
|
|
104
82
|
program
|
package/dist/judge/factory.d.ts
CHANGED
|
@@ -7,8 +7,6 @@ type Env = Record<string, string | undefined>;
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const BUNDLED_PROVIDERS: Record<string, ModelProviderConfig>;
|
|
9
9
|
/** Semantic evaluation is misconfigured (no provider, unknown provider, missing key). Reported as a plain CLI error. */
|
|
10
|
-
export declare class JudgeConfigError extends Error {
|
|
11
|
-
}
|
|
12
10
|
/**
|
|
13
11
|
* Hydrate a provider definition into concrete values, in one place. Per field: the explicit value
|
|
14
12
|
* wins, then the named environment variable if it is set (a set-but-empty variable is an error, not
|
|
@@ -29,7 +27,7 @@ export declare function judgeForRun(config: Parameters<typeof createJudge>[0], s
|
|
|
29
27
|
/**
|
|
30
28
|
* The provider for a run: the one named by `name` (the `--semantic <provider>` override), else the space's
|
|
31
29
|
* `semantic.provider`, else the top-level one. The name resolves against `modelProviders` first, then
|
|
32
|
-
* the bundled providers. Throws {@link
|
|
30
|
+
* the bundled providers. Throws {@link SctxError} `E_MODEL_PROVIDER_INVALID` when it cannot be built.
|
|
33
31
|
*/
|
|
34
32
|
export declare function createJudge(config: {
|
|
35
33
|
modelProviders?: Record<string, ModelProviderConfig>;
|
package/dist/judge/factory.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SctxError } from '../errors';
|
|
1
2
|
import { AnthropicJudgeProvider, RECOMMENDED_ANTHROPIC_MODEL } from './provider/anthropic';
|
|
2
3
|
import { FakeJudgeProvider } from './provider/fake';
|
|
3
4
|
import { JEV_LATEST, JevJudgeProvider } from './provider/jev';
|
|
@@ -66,8 +67,6 @@ const DEFAULT_KEY_ENV = {
|
|
|
66
67
|
'typesafe-systemone': 'TYPESAFE_API_KEY',
|
|
67
68
|
};
|
|
68
69
|
/** Semantic evaluation is misconfigured (no provider, unknown provider, missing key). Reported as a plain CLI error. */
|
|
69
|
-
export class JudgeConfigError extends Error {
|
|
70
|
-
}
|
|
71
70
|
/**
|
|
72
71
|
* Hydrate a provider definition into concrete values, in one place. Per field: the explicit value
|
|
73
72
|
* wins, then the named environment variable if it is set (a set-but-empty variable is an error, not
|
|
@@ -75,7 +74,7 @@ export class JudgeConfigError extends Error {
|
|
|
75
74
|
*/
|
|
76
75
|
export function hydrateProvider(name, def, env = process.env) {
|
|
77
76
|
if (!MODEL_PROVIDER_APIS.includes(def.api)) {
|
|
78
|
-
throw new
|
|
77
|
+
throw new SctxError('E_MODEL_PROVIDER_INVALID', `Model provider "${name}" has unknown api "${def.api}". Use one of: ${MODEL_PROVIDER_APIS.join(', ')}.`);
|
|
79
78
|
}
|
|
80
79
|
const fromEnv = (value, envName) => {
|
|
81
80
|
if (value !== undefined)
|
|
@@ -84,7 +83,7 @@ export function hydrateProvider(name, def, env = process.env) {
|
|
|
84
83
|
return undefined;
|
|
85
84
|
const envValue = env[envName];
|
|
86
85
|
if (envValue !== undefined && envValue.trim() === '') {
|
|
87
|
-
throw new
|
|
86
|
+
throw new SctxError('E_MODEL_PROVIDER_INVALID', `Model provider "${name}" has ${envName} set but empty; set a value or unset the variable.`);
|
|
88
87
|
}
|
|
89
88
|
return envValue;
|
|
90
89
|
};
|
|
@@ -104,7 +103,7 @@ export function createModelProvider(name, def, env = process.env) {
|
|
|
104
103
|
// OpenAI-compatible endpoints (Ollama, vLLM, ...) may need no key; the others must resolve one.
|
|
105
104
|
// A key never borrows another provider's variable: only the named apiKeyEnv (or literal apiKey) counts.
|
|
106
105
|
if (!h.apiKey && h.api !== 'openai-completions' && h.api !== 'fake') {
|
|
107
|
-
throw new
|
|
106
|
+
throw new SctxError('E_MODEL_PROVIDER_INVALID', `Model provider "${name}" (${h.api}) has no API key. Set ${h.keyEnv} in the environment, or "apiKey" / "apiKeyEnv" on the provider.`);
|
|
108
107
|
}
|
|
109
108
|
switch (h.api) {
|
|
110
109
|
case 'fake':
|
|
@@ -132,17 +131,17 @@ export function judgeForRun(config, space, semantic) {
|
|
|
132
131
|
/**
|
|
133
132
|
* The provider for a run: the one named by `name` (the `--semantic <provider>` override), else the space's
|
|
134
133
|
* `semantic.provider`, else the top-level one. The name resolves against `modelProviders` first, then
|
|
135
|
-
* the bundled providers. Throws {@link
|
|
134
|
+
* the bundled providers. Throws {@link SctxError} `E_MODEL_PROVIDER_INVALID` when it cannot be built.
|
|
136
135
|
*/
|
|
137
136
|
export function createJudge(config, space = {}, name, env = process.env) {
|
|
138
137
|
const chosen = name ?? space.semantic?.provider ?? config.semantic?.provider;
|
|
139
138
|
if (!chosen) {
|
|
140
|
-
throw new
|
|
139
|
+
throw new SctxError('E_MODEL_PROVIDER_INVALID', '--semantic needs a model provider. Set "semantic.provider" in config.json, or pass --semantic <provider>.');
|
|
141
140
|
}
|
|
142
141
|
const def = config.modelProviders?.[chosen] ?? BUNDLED_PROVIDERS[chosen];
|
|
143
142
|
if (!def) {
|
|
144
143
|
const known = [...Object.keys(BUNDLED_PROVIDERS), ...Object.keys(config.modelProviders ?? {})];
|
|
145
|
-
throw new
|
|
144
|
+
throw new SctxError('E_MODEL_PROVIDER_INVALID', `Model provider "${chosen}" is not configured.${known.length ? ` Known providers: ${known.join(', ')}.` : ''}`);
|
|
146
145
|
}
|
|
147
146
|
return createModelProvider(chosen, def, env);
|
|
148
147
|
}
|
package/dist/space-context.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { type Config } from './config';
|
|
2
2
|
import type { SpaceContext } from './types';
|
|
3
|
-
/** Thrown by createSpaceContext when no space matches the given name. */
|
|
4
|
-
export declare class SpaceNotFoundError extends Error {
|
|
5
|
-
readonly spaceName: string;
|
|
6
|
-
constructor(spaceName: string);
|
|
7
|
-
}
|
|
8
3
|
export interface CreateSpaceContextOptions {
|
|
9
4
|
/**
|
|
10
5
|
* Directory to anchor relative plugin-config paths against. Defaults to the source
|
|
@@ -20,8 +15,7 @@ export interface CreateSpaceContextOptions {
|
|
|
20
15
|
* Synchronously resolves schemas (including plugin-contributed schemas),
|
|
21
16
|
* indexes partials into the registry, and compiles the schema validator.
|
|
22
17
|
*
|
|
23
|
-
* Library-safe: throws
|
|
24
|
-
* writing to the console or exiting the process.
|
|
25
|
-
* exit-on-error behaviour should wrap this (see buildSpaceContext in index.ts).
|
|
18
|
+
* Library-safe: throws SctxError (E_SPACE_NOT_FOUND) on an unknown space rather than
|
|
19
|
+
* writing to the console or exiting the process.
|
|
26
20
|
*/
|
|
27
21
|
export declare function createSpaceContext(spaceName: string, config: Config, options?: CreateSpaceContextOptions): SpaceContext;
|
package/dist/space-context.js
CHANGED
|
@@ -2,29 +2,19 @@ import { resolveSchema } from './config';
|
|
|
2
2
|
import { SctxError } from './errors';
|
|
3
3
|
import { resolveSpacePluginSchemas } from './plugins/util';
|
|
4
4
|
import { loadSchema } from './schema/schema';
|
|
5
|
-
/** Thrown by createSpaceContext when no space matches the given name. */
|
|
6
|
-
export class SpaceNotFoundError extends Error {
|
|
7
|
-
spaceName;
|
|
8
|
-
constructor(spaceName) {
|
|
9
|
-
super(`Unknown space "${spaceName}"`);
|
|
10
|
-
this.spaceName = spaceName;
|
|
11
|
-
this.name = 'SpaceNotFoundError';
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
5
|
/**
|
|
15
6
|
* Build a SpaceContext for a named space from an already-loaded config.
|
|
16
7
|
*
|
|
17
8
|
* Synchronously resolves schemas (including plugin-contributed schemas),
|
|
18
9
|
* indexes partials into the registry, and compiles the schema validator.
|
|
19
10
|
*
|
|
20
|
-
* Library-safe: throws
|
|
21
|
-
* writing to the console or exiting the process.
|
|
22
|
-
* exit-on-error behaviour should wrap this (see buildSpaceContext in index.ts).
|
|
11
|
+
* Library-safe: throws SctxError (E_SPACE_NOT_FOUND) on an unknown space rather than
|
|
12
|
+
* writing to the console or exiting the process.
|
|
23
13
|
*/
|
|
24
14
|
export function createSpaceContext(spaceName, config, options = {}) {
|
|
25
15
|
const space = config.spaces.find((s) => s.name === spaceName);
|
|
26
16
|
if (!space) {
|
|
27
|
-
throw new
|
|
17
|
+
throw new SctxError('E_SPACE_NOT_FOUND', `Unknown space "${spaceName}"`);
|
|
28
18
|
}
|
|
29
19
|
const configDir = options.configDir ?? space.sourceDir;
|
|
30
20
|
if (configDir === undefined) {
|
package/dist/validate.d.ts
CHANGED
|
@@ -62,26 +62,64 @@ export interface ValidationResult {
|
|
|
62
62
|
* Groups related errors and extracts helpful context like allowed values.
|
|
63
63
|
*/
|
|
64
64
|
export declare function formatErrors(errors: ErrorObject[], schema: SchemaWithMetadata, schemaRefRegistry: Parameters<typeof extractEntityInfo>[1], nodeData: Record<string, unknown>): FormattedError[];
|
|
65
|
-
|
|
66
|
-
readResult?: ReadSpaceResult;
|
|
67
|
-
/** Limit validation to hierarchy nodes within N breadth-first levels from the top. */
|
|
68
|
-
depth?: number;
|
|
65
|
+
interface CommonValidateOptions {
|
|
69
66
|
/** Evaluate rules on gated nodes anyway (gates are still reported). */
|
|
70
67
|
includeGated?: boolean;
|
|
71
|
-
/** Evaluate only rules matching
|
|
68
|
+
/** Evaluate only rules matching these `dimension=values` filters (category, severity, type, id). */
|
|
69
|
+
ruleFilter?: string[];
|
|
70
|
+
/**
|
|
71
|
+
* Evaluate `semantic` rules with the model provider named here, or with the configured one for `true`.
|
|
72
|
+
* Without it, a rule runs only its `expression`, and a semantic-only rule is skipped.
|
|
73
|
+
*/
|
|
74
|
+
semantic?: boolean | string;
|
|
75
|
+
}
|
|
76
|
+
/** What a run evaluates with: the public options after the filter is parsed and the judge is built. */
|
|
77
|
+
export interface RunOptions {
|
|
78
|
+
includeGated?: boolean;
|
|
72
79
|
ruleFilter?: RuleFilter;
|
|
73
|
-
/** Evaluates `semantic` rules. Without one, a rule runs only its `expression`, and a semantic-only rule is skipped. */
|
|
74
80
|
judge?: SemanticJudgeProvider;
|
|
81
|
+
/** Limit judging to one file (and the ancestors that can gate it). */
|
|
82
|
+
judgeTarget?: string;
|
|
83
|
+
}
|
|
84
|
+
export interface ValidateSpaceOptions extends CommonValidateOptions {
|
|
85
|
+
readResult?: ReadSpaceResult;
|
|
86
|
+
/** Limit validation to hierarchy nodes within N breadth-first levels from the top. */
|
|
87
|
+
depth?: number;
|
|
75
88
|
}
|
|
76
89
|
/** `file`, `file:line` or `file:line:column`, for messages. */
|
|
77
90
|
export declare function formatSource({ file, line, column }: SourceLocation): string;
|
|
78
91
|
/** One-line text for a rule violation: rule, description, and any evidence and verdict guidance. */
|
|
79
92
|
export declare function ruleViolationMessage(v: RuleViolation): string;
|
|
93
|
+
/** A node that failed type or schema validation. */
|
|
94
|
+
interface NodeValidationFailure {
|
|
95
|
+
node: SpaceNode;
|
|
96
|
+
issues: FormattedError[];
|
|
97
|
+
}
|
|
98
|
+
/** The outcome of validating a set of nodes, before either view shapes it. */
|
|
99
|
+
export interface SpaceValidationResult {
|
|
100
|
+
validCount: number;
|
|
101
|
+
nodeFailures: NodeValidationFailure[];
|
|
102
|
+
refErrors: ValidationResult['refErrors'];
|
|
103
|
+
duplicateErrors: ValidationResult['duplicateErrors'];
|
|
104
|
+
ruleViolations: RuleViolation[];
|
|
105
|
+
hierarchyViolations: GraphViolation[];
|
|
106
|
+
orphans: SpaceNode[];
|
|
107
|
+
unresolvedContentLinks: ValidationResult['unresolvedContentLinks'];
|
|
108
|
+
coverageGates: CoverageGate[];
|
|
109
|
+
contextTrimmed: ValidationResult['contextTrimmed'];
|
|
110
|
+
}
|
|
80
111
|
/**
|
|
81
112
|
* Nodes that share an id, with where each is defined. A plugin should keep ids unique, so this guards that contract.
|
|
82
113
|
* Display titles may repeat.
|
|
83
114
|
*/
|
|
84
115
|
export declare function findDuplicateIds(nodes: SpaceNode[]): ValidationResult['duplicateErrors'];
|
|
116
|
+
/**
|
|
117
|
+
* The one validation pipeline: type and schema checks, duplicate titles, reference and hierarchy
|
|
118
|
+
* checks, cascade-gated rules, and unresolved content links. Returns every entry; `validateSpace`
|
|
119
|
+
* and `validateFile` are views over it, so a file's results match its entry in a full run.
|
|
120
|
+
* `judgeTarget` limits judging to one file (and the ancestors that can gate it).
|
|
121
|
+
*/
|
|
122
|
+
export declare function validateNodes(context: SpaceContext, nodes: SpaceNode[], unresolvedRefs: ReadSpaceResult['unresolvedRefs'], options?: RunOptions): Promise<SpaceValidationResult>;
|
|
85
123
|
/**
|
|
86
124
|
* Run full validation on a space and return a structured result.
|
|
87
125
|
* Does not output to console or call process.exit.
|
|
@@ -92,14 +130,8 @@ export declare function resolveFileSpace(filePath: string, config: Config): {
|
|
|
92
130
|
space: SpaceConfig;
|
|
93
131
|
label: string;
|
|
94
132
|
} | null;
|
|
95
|
-
export interface ValidateFileOptions {
|
|
133
|
+
export interface ValidateFileOptions extends CommonValidateOptions {
|
|
96
134
|
configDir?: string;
|
|
97
|
-
/** Evaluate rules on gated nodes anyway (gates are still reported). */
|
|
98
|
-
includeGated?: boolean;
|
|
99
|
-
/** Evaluate only rules matching this filter (see `parseRuleFilter`). */
|
|
100
|
-
ruleFilter?: RuleFilter;
|
|
101
|
-
/** Evaluates `semantic` rules. Without one, a rule runs only its `expression`, and a semantic-only rule is skipped. */
|
|
102
|
-
judge?: SemanticJudgeProvider;
|
|
103
135
|
}
|
|
104
136
|
/** The result for a file that belongs to no configured space. */
|
|
105
137
|
export declare function fileNotInSpace(filePath: string): FileNotInSpaceResult;
|
|
@@ -108,6 +140,8 @@ export declare function fileNotInSpace(filePath: string): FileNotInSpaceResult;
|
|
|
108
140
|
* correctness), judging only the file, then selects the file's issues from the result.
|
|
109
141
|
*/
|
|
110
142
|
export declare function validateResolvedFile(filePath: string, label: string, context: SpaceContext, options?: Omit<ValidateFileOptions, 'configDir'>): Promise<FileValidationResult>;
|
|
143
|
+
/** `validateResolvedFile` with the options already resolved, so a caller can supply its own judge. */
|
|
144
|
+
export declare function validateResolvedFileWith(filePath: string, label: string, context: SpaceContext, runOptions: RunOptions): Promise<FileValidationResult>;
|
|
111
145
|
/**
|
|
112
146
|
* Validate a single file within its space.
|
|
113
147
|
*
|
|
@@ -118,3 +152,4 @@ export declare function validateResolvedFile(filePath: string, label: string, co
|
|
|
118
152
|
* If the file is not in any configured space, returns a result with `inSpace: false`.
|
|
119
153
|
*/
|
|
120
154
|
export declare function validateFile(filePath: string, config: Config, options?: ValidateFileOptions): Promise<ValidateFileOutput>;
|
|
155
|
+
export {};
|
package/dist/validate.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { isAbsolute, relative, resolve } from 'node:path';
|
|
2
|
+
import { judgeForRun } from './judge/factory';
|
|
2
3
|
import { readSpace } from './read/read-space';
|
|
3
4
|
import { computeHierarchyDepths, evaluateRulesWithGating } from './schema/gating';
|
|
4
|
-
import { filterRules } from './schema/rule-filter';
|
|
5
|
+
import { filterRules, parseRuleFilter } from './schema/rule-filter';
|
|
5
6
|
import { extractEntityInfo, typeValidatorFor } from './schema/schema';
|
|
6
7
|
import { validateGraph } from './schema/validate-graph';
|
|
7
8
|
import { validateRules } from './schema/validate-rules';
|
|
@@ -94,6 +95,14 @@ export function formatErrors(errors, schema, schemaRefRegistry, nodeData) {
|
|
|
94
95
|
}
|
|
95
96
|
return formatted;
|
|
96
97
|
}
|
|
98
|
+
/** Throws `SctxError` `E_MODEL_PROVIDER_INVALID` when `semantic` names a provider that cannot be built. */
|
|
99
|
+
function runOptionsFrom(context, options) {
|
|
100
|
+
return {
|
|
101
|
+
includeGated: options.includeGated,
|
|
102
|
+
ruleFilter: options.ruleFilter && parseRuleFilter(options.ruleFilter),
|
|
103
|
+
judge: judgeForRun(context.config, context.space, options.semantic),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
97
106
|
/** `file`, `file:line` or `file:line:column`, for messages. */
|
|
98
107
|
export function formatSource({ file, line, column }) {
|
|
99
108
|
return line === undefined ? file : `${file}:${line}${column === undefined ? '' : `:${column}`}`;
|
|
@@ -159,7 +168,7 @@ export function findDuplicateIds(nodes) {
|
|
|
159
168
|
* and `validateFile` are views over it, so a file's results match its entry in a full run.
|
|
160
169
|
* `judgeTarget` limits judging to one file (and the ancestors that can gate it).
|
|
161
170
|
*/
|
|
162
|
-
async function validateNodes(context, nodes, unresolvedRefs, options = {}) {
|
|
171
|
+
export async function validateNodes(context, nodes, unresolvedRefs, options = {}) {
|
|
163
172
|
const { schema, schemaRefRegistry, schemaValidator } = context;
|
|
164
173
|
const metadata = schema.metadata;
|
|
165
174
|
// Pre-extract valid types for early type validation
|
|
@@ -248,6 +257,7 @@ async function validateNodes(context, nodes, unresolvedRefs, options = {}) {
|
|
|
248
257
|
*/
|
|
249
258
|
export async function validateSpace(context, options = {}) {
|
|
250
259
|
const metadata = context.schema.metadata;
|
|
260
|
+
const runOptions = runOptionsFrom(context, options);
|
|
251
261
|
const readResult = options.readResult ?? (await readSpace(context));
|
|
252
262
|
let nodes = readResult.nodes;
|
|
253
263
|
// Depth limiting: evaluate only hierarchy nodes within N breadth-first levels from the
|
|
@@ -268,11 +278,7 @@ export async function validateSpace(context, options = {}) {
|
|
|
268
278
|
}
|
|
269
279
|
nodes = included;
|
|
270
280
|
}
|
|
271
|
-
const result = await validateNodes(context, nodes, readResult.unresolvedRefs,
|
|
272
|
-
includeGated: options.includeGated,
|
|
273
|
-
ruleFilter: options.ruleFilter,
|
|
274
|
-
judge: options.judge,
|
|
275
|
-
});
|
|
281
|
+
const result = await validateNodes(context, nodes, readResult.unresolvedRefs, runOptions);
|
|
276
282
|
return {
|
|
277
283
|
validCount: result.validCount,
|
|
278
284
|
nodeErrorCount: result.nodeFailures.length,
|
|
@@ -390,15 +396,17 @@ export function fileNotInSpace(filePath) {
|
|
|
390
396
|
* Validate a file in an already-resolved space. Checks the whole space (required for graph
|
|
391
397
|
* correctness), judging only the file, then selects the file's issues from the result.
|
|
392
398
|
*/
|
|
393
|
-
export
|
|
399
|
+
export function validateResolvedFile(filePath, label, context, options = {}) {
|
|
400
|
+
return validateResolvedFileWith(filePath, label, context, runOptionsFrom(context, options));
|
|
401
|
+
}
|
|
402
|
+
/** `validateResolvedFile` with the options already resolved, so a caller can supply its own judge. */
|
|
403
|
+
export async function validateResolvedFileWith(filePath, label, context, runOptions) {
|
|
394
404
|
const readResult = await readSpace(context);
|
|
395
405
|
const result = await validateNodes(context, readResult.nodes, readResult.unresolvedRefs, {
|
|
396
|
-
|
|
397
|
-
ruleFilter: options.ruleFilter,
|
|
398
|
-
judge: options.judge,
|
|
406
|
+
...runOptions,
|
|
399
407
|
judgeTarget: label,
|
|
400
408
|
});
|
|
401
|
-
const { errors, warnings } = issuesForFile(result, label,
|
|
409
|
+
const { errors, warnings } = issuesForFile(result, label, runOptions.includeGated);
|
|
402
410
|
return {
|
|
403
411
|
file: isAbsolute(filePath) ? filePath : resolve(process.cwd(), filePath),
|
|
404
412
|
label,
|
package/package.json
CHANGED
package/dist/judge/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export { createJudge, createModelProvider, JudgeConfigError } from './factory';
|
|
2
|
-
export { buildJudgeSystemPrompt, buildJudgeUserPrompt, parseJudgeResponse } from './prompt';
|
|
3
|
-
export type { AnthropicJudgeProviderOptions } from './provider/anthropic';
|
|
4
|
-
export { AnthropicJudgeProvider } from './provider/anthropic';
|
|
5
|
-
export type { FakeAnswer, FakeJudgeHandler } from './provider/fake';
|
|
6
|
-
export { FakeJudgeProvider } from './provider/fake';
|
|
7
|
-
export type { JevJudgeProviderOptions } from './provider/jev';
|
|
8
|
-
export { JevJudgeProvider } from './provider/jev';
|
|
9
|
-
export type { OpenAIJudgeProviderOptions } from './provider/openai';
|
|
10
|
-
export { OpenAIJudgeProvider } from './provider/openai';
|
|
11
|
-
export { PerRuleJudgeProvider } from './provider/per-rule';
|
|
12
|
-
export type { JudgeConfig, ModelProviderConfig, SemanticJudgeInput, SemanticJudgeProvider, SemanticJudgeResult, SemanticJudgeVerdict, SemanticRuleSpec, } from './types';
|
|
13
|
-
export { DEFAULT_VERDICTS, isJudgeError, semanticRuleSpec } from './verdicts';
|
package/dist/judge/index.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export { createJudge, createModelProvider, JudgeConfigError } from './factory';
|
|
2
|
-
export { buildJudgeSystemPrompt, buildJudgeUserPrompt, parseJudgeResponse } from './prompt';
|
|
3
|
-
export { AnthropicJudgeProvider } from './provider/anthropic';
|
|
4
|
-
export { FakeJudgeProvider } from './provider/fake';
|
|
5
|
-
export { JevJudgeProvider } from './provider/jev';
|
|
6
|
-
export { OpenAIJudgeProvider } from './provider/openai';
|
|
7
|
-
export { PerRuleJudgeProvider } from './provider/per-rule';
|
|
8
|
-
export { DEFAULT_VERDICTS, isJudgeError, semanticRuleSpec } from './verdicts';
|