structured-context 0.11.0 → 0.13.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 (138) hide show
  1. package/README.md +52 -198
  2. package/dist/api.d.ts +17 -15
  3. package/dist/api.js +12 -9
  4. package/dist/commands/diagram.d.ts +1 -0
  5. package/dist/commands/diagram.js +7 -1
  6. package/dist/commands/docs.js +1 -0
  7. package/dist/commands/dump.d.ts +15 -2
  8. package/dist/commands/dump.js +18 -4
  9. package/dist/commands/providers.d.ts +4 -0
  10. package/dist/commands/providers.js +52 -0
  11. package/dist/commands/render.d.ts +4 -0
  12. package/dist/commands/render.js +64 -9
  13. package/dist/commands/schemas.d.ts +2 -2
  14. package/dist/commands/schemas.js +133 -22
  15. package/dist/commands/show.d.ts +1 -0
  16. package/dist/commands/show.js +7 -1
  17. package/dist/commands/spaces.d.ts +3 -1
  18. package/dist/commands/spaces.js +11 -2
  19. package/dist/commands/validate-file.d.ts +3 -0
  20. package/dist/commands/validate-file.js +24 -6
  21. package/dist/commands/validate.d.ts +4 -0
  22. package/dist/commands/validate.js +79 -23
  23. package/dist/config.d.ts +25 -1
  24. package/dist/config.js +106 -12
  25. package/dist/filter/augment-nodes.d.ts +3 -1
  26. package/dist/filter/augment-nodes.js +12 -7
  27. package/dist/filter/filter-nodes.js +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +96 -31
  30. package/dist/judge/context.d.ts +20 -0
  31. package/dist/judge/context.js +105 -0
  32. package/dist/judge/factory.d.ts +44 -0
  33. package/dist/judge/factory.js +148 -0
  34. package/dist/judge/index.d.ts +13 -0
  35. package/dist/judge/index.js +8 -0
  36. package/dist/judge/judge-node.d.ts +27 -0
  37. package/dist/judge/judge-node.js +122 -0
  38. package/dist/judge/prompt.d.ts +10 -0
  39. package/dist/judge/prompt.js +92 -0
  40. package/dist/judge/provider/anthropic.d.ts +17 -0
  41. package/dist/judge/provider/anthropic.js +43 -0
  42. package/dist/judge/provider/fake.d.ts +26 -0
  43. package/dist/judge/provider/fake.js +56 -0
  44. package/dist/judge/provider/jev.d.ts +37 -0
  45. package/dist/judge/provider/jev.js +169 -0
  46. package/dist/judge/provider/openai-decisions.d.ts +21 -0
  47. package/dist/judge/provider/openai-decisions.js +84 -0
  48. package/dist/judge/provider/openai.d.ts +20 -0
  49. package/dist/judge/provider/openai.js +53 -0
  50. package/dist/judge/provider/per-rule.d.ts +10 -0
  51. package/dist/judge/provider/per-rule.js +18 -0
  52. package/dist/judge/trim.d.ts +27 -0
  53. package/dist/judge/trim.js +62 -0
  54. package/dist/judge/types.d.ts +92 -0
  55. package/dist/judge/types.js +9 -0
  56. package/dist/judge/verdicts.d.ts +24 -0
  57. package/dist/judge/verdicts.js +82 -0
  58. package/dist/load-space-graph.d.ts +7 -5
  59. package/dist/load-space-graph.js +19 -8
  60. package/dist/plugins/loader.js +3 -3
  61. package/dist/plugins/markdown/extract-content-links.js +8 -29
  62. package/dist/plugins/markdown/index.js +8 -2
  63. package/dist/plugins/markdown/parse-embedded.d.ts +8 -0
  64. package/dist/plugins/markdown/parse-embedded.js +195 -24
  65. package/dist/plugins/markdown/read-space.js +42 -14
  66. package/dist/plugins/markdown/render-directory.d.ts +11 -0
  67. package/dist/plugins/markdown/render-directory.js +130 -0
  68. package/dist/plugins/markdown/template-sync.js +3 -4
  69. package/dist/plugins/markdown/util.d.ts +26 -5
  70. package/dist/plugins/markdown/util.js +56 -15
  71. package/dist/plugins/mermaid/render-mermaid.js +2 -1
  72. package/dist/plugins/miro/sync.js +7 -6
  73. package/dist/plugins/util.d.ts +39 -1
  74. package/dist/plugins/util.js +139 -0
  75. package/dist/read/resolve-graph-edges.d.ts +1 -1
  76. package/dist/read/resolve-graph-edges.js +46 -27
  77. package/dist/read/wikilink-utils.d.ts +17 -0
  78. package/dist/read/wikilink-utils.js +40 -0
  79. package/dist/render/render.d.ts +3 -1
  80. package/dist/render/render.js +2 -2
  81. package/dist/schema/evaluate-rule.d.ts +33 -2
  82. package/dist/schema/evaluate-rule.js +58 -4
  83. package/dist/schema/gating.d.ts +69 -0
  84. package/dist/schema/gating.js +253 -0
  85. package/dist/schema/meta-schemas.d.ts +13 -0
  86. package/dist/schema/meta-schemas.js +50 -0
  87. package/dist/schema/metadata-contract.d.ts +952 -183
  88. package/dist/schema/metadata-contract.js +177 -33
  89. package/dist/schema/rule-filter.d.ts +12 -0
  90. package/dist/schema/rule-filter.js +46 -0
  91. package/dist/schema/rule-severity.d.ts +13 -0
  92. package/dist/schema/rule-severity.js +33 -0
  93. package/dist/schema/schema.d.ts +14 -8
  94. package/dist/schema/schema.js +308 -199
  95. package/dist/schema/validate-graph.d.ts +2 -1
  96. package/dist/schema/validate-graph.js +40 -23
  97. package/dist/schema/validate-rules.d.ts +16 -3
  98. package/dist/schema/validate-rules.js +91 -29
  99. package/dist/schemas/_knowledge_wiki.json +24 -24
  100. package/dist/schemas/_okf.json +172 -0
  101. package/dist/schemas/_ost_strict.json +17 -8
  102. package/dist/schemas/_sctx_base.json +3 -3
  103. package/dist/schemas/_strategy_general.json +38 -38
  104. package/dist/schemas/generated/0.12.0/_structured_context_schema_meta.json +229 -0
  105. package/dist/schemas/generated/0.13.0/_structured_context_schema_meta.json +400 -0
  106. package/dist/schemas/generated/latest/_structured_context_schema_meta.json +400 -0
  107. package/dist/schemas/knowledge_wiki.json +10 -9
  108. package/dist/schemas/okf.json +8 -0
  109. package/dist/schemas/strategy_general.json +15 -14
  110. package/dist/schemas/strict_ost.json +17 -16
  111. package/dist/space-context.d.ts +5 -2
  112. package/dist/space-context.js +9 -4
  113. package/dist/space-graph.d.ts +9 -7
  114. package/dist/space-graph.js +7 -5
  115. package/dist/testing.d.ts +33 -0
  116. package/dist/testing.js +72 -0
  117. package/dist/types.d.ts +64 -16
  118. package/dist/validate.d.ts +62 -9
  119. package/dist/validate.js +229 -114
  120. package/docs/concepts.md +65 -9
  121. package/docs/config.md +78 -1
  122. package/docs/rules.md +168 -50
  123. package/docs/schemas.md +152 -52
  124. package/package.json +17 -11
  125. package/schemas/_knowledge_wiki.json +24 -24
  126. package/schemas/_okf.json +172 -0
  127. package/schemas/_ost_strict.json +17 -8
  128. package/schemas/_sctx_base.json +3 -3
  129. package/schemas/_strategy_general.json +38 -38
  130. package/schemas/generated/0.12.0/_structured_context_schema_meta.json +229 -0
  131. package/schemas/generated/0.13.0/_structured_context_schema_meta.json +400 -0
  132. package/schemas/generated/latest/_structured_context_schema_meta.json +400 -0
  133. package/schemas/knowledge_wiki.json +10 -9
  134. package/schemas/okf.json +8 -0
  135. package/schemas/strategy_general.json +15 -14
  136. package/schemas/strict_ost.json +17 -16
  137. package/dist/schemas/generated/_structured_context_schema_meta.json +0 -191
  138. package/schemas/generated/_structured_context_schema_meta.json +0 -191
@@ -1,4 +1,13 @@
1
- export const SCHEMA_META_ID = 'https://raw.githubusercontent.com/mindsocket/structured-context/main/schemas/generated/_structured_context_schema_meta.json';
1
+ /** The JSON Schema dialect the structured-context dialect extends. */
2
+ export const JSON_SCHEMA_DIALECT = 'https://json-schema.org/draft/2020-12/schema';
3
+ export const SCHEMA_META_BASE_URL = 'https://raw.githubusercontent.com/mindsocket/structured-context/main/schemas/generated';
4
+ export const SCHEMA_META_FILE = '_structured_context_schema_meta.json';
5
+ /** Meta-schema `$id` for a dialect version folder, e.g. `.../generated/0.12.0/_structured_context_schema_meta.json`. */
6
+ export function schemaMetaId(folder) {
7
+ return `${SCHEMA_META_BASE_URL}/${folder}/${SCHEMA_META_FILE}`;
8
+ }
9
+ /** The URL schemas set as `$schema` to follow the newest dialect. Resolves to the newest versioned meta-schema. */
10
+ export const SCHEMA_META_ID = schemaMetaId('latest');
2
11
  /** Graph edge routing fields shared by hierarchy levels and relationships. */
3
12
  const EDGE_PROPS = {
4
13
  field: { type: 'string', minLength: 1 },
@@ -34,21 +43,128 @@ const HIERARCHY_LEVEL_SCHEMA = {
34
43
  required: ['type'],
35
44
  additionalProperties: false,
36
45
  };
46
+ const SEVERITY_SCHEMA = { enum: ['error', 'warning', 'info'] };
47
+ /** The verdicts the evaluation reserves besides a rule's own; a verdict map may set a severity for them. */
48
+ export const RESERVED_VERDICTS = ['missing-context'];
49
+ /** Related-node kinds a semantic rule's `scope` can add: main-hierarchy edges only. `branch` is ancestors plus descendants. */
50
+ export const SEMANTIC_SCOPES = ['parent', 'siblings', 'children', 'ancestors', 'descendants', 'branch'];
51
+ const VERDICT_SEVERITY_SCHEMA = { enum: ['error', 'warning', 'info', 'ignore'] };
52
+ /** The semantic part of a rule: a model evaluates the node against a rubric and returns a verdict. */
53
+ const SEMANTIC_SCHEMA = {
54
+ type: 'object',
55
+ properties: {
56
+ /** What the model judges the node against. Falls back to the rule's `description`. */
57
+ rubric: { type: 'string', minLength: 1 },
58
+ /**
59
+ * The closed set of verdicts the model may return. Each is a description (what the verdict means, for the
60
+ * model) or `{ description, guidance }`, where `guidance` is shown to the user when it fires.
61
+ * Defaults to `pass`/`fail`.
62
+ */
63
+ verdicts: {
64
+ type: 'object',
65
+ additionalProperties: {
66
+ oneOf: [
67
+ { type: 'string', minLength: 1 },
68
+ {
69
+ type: 'object',
70
+ properties: { description: { type: 'string', minLength: 1 }, guidance: { type: 'string', minLength: 1 } },
71
+ required: ['description'],
72
+ additionalProperties: false,
73
+ },
74
+ ],
75
+ },
76
+ minProperties: 2,
77
+ },
78
+ /**
79
+ * Severity per verdict in effect (declared, default or reserved). A verdict mapped to `ignore` is judged but
80
+ * not reported, and a verdict left out passes. Required with `verdicts`; with the default verdicts, `fail`
81
+ * takes the rule's own `severity` instead.
82
+ */
83
+ severity: {
84
+ type: 'object',
85
+ additionalProperties: VERDICT_SEVERITY_SCHEMA,
86
+ minProperties: 1,
87
+ },
88
+ /**
89
+ * Related nodes, along main-hierarchy edges, sent with the evaluated node. Additive; left out or empty means
90
+ * the evaluated node alone.
91
+ */
92
+ scope: {
93
+ type: 'array',
94
+ items: { enum: SEMANTIC_SCOPES },
95
+ uniqueItems: true,
96
+ },
97
+ /**
98
+ * Which node bodies are sent: `nodeOnly` (the evaluated node's), `fullScope` (it and every related node's),
99
+ * or `true` for `fullScope`. Left out: no bodies.
100
+ */
101
+ includeContent: { enum: ['nodeOnly', 'fullScope', true] },
102
+ },
103
+ additionalProperties: false,
104
+ };
37
105
  const RULE_SCHEMA = {
38
106
  type: 'object',
39
107
  properties: {
40
108
  id: { type: 'string', minLength: 1 },
41
109
  category: { enum: ['validation', 'coherence', 'workflow', 'best-practice'] },
110
+ /**
111
+ * Severity of a failed `expression` and of the default `fail` verdict. Defaults from the category.
112
+ */
113
+ severity: SEVERITY_SCHEMA,
42
114
  description: { type: 'string', minLength: 1 },
43
- check: { type: 'string', minLength: 1 },
115
+ /** JSONata test a node must pass. When the rule also has `semantic`, a failing node is reported without being evaluated by the model. */
116
+ expression: { type: 'string', minLength: 1 },
117
+ /** Optional JSONata applicability condition, evaluated per node before the rule runs. The rule applies only when it returns true. */
118
+ when: { type: 'string', minLength: 1 },
119
+ /** A model evaluates the node against a rubric. `{}` takes every default; `true` means the same. */
120
+ semantic: { oneOf: [{ const: true }, SEMANTIC_SCHEMA] },
44
121
  type: { type: 'string', minLength: 1 },
45
- scope: { enum: ['global'] },
122
+ /** Run once for the whole space instead of once per node. */
123
+ global: { type: 'boolean' },
46
124
  override: { type: 'boolean' },
125
+ /** Whether a failure of this rule gates (suppresses) downstream rules on the node's hierarchy subtree. Defaults to true when the failure's severity is `error`. */
126
+ gatesDescendants: { type: 'boolean' },
47
127
  },
48
- required: ['id', 'category', 'description', 'check'],
128
+ required: ['id', 'category', 'description'],
49
129
  additionalProperties: false,
130
+ allOf: [
131
+ // A rule has an expression, a semantic part, or both.
132
+ { anyOf: [{ required: ['expression'] }, { required: ['semantic'] }] },
133
+ // A global rule has no node to apply to or to evaluate.
134
+ {
135
+ if: { required: ['global'], properties: { global: { const: true } } },
136
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema `if`/`then` keyword, not a thenable
137
+ then: { not: { anyOf: [{ required: ['when'] }, { required: ['type'] }, { required: ['semantic'] }] } },
138
+ },
139
+ // Custom verdicts need a severity for each failing verdict.
140
+ {
141
+ if: { required: ['semantic'], properties: { semantic: { type: 'object', required: ['verdicts'] } } },
142
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema `if`/`then` keyword, not a thenable
143
+ then: { properties: { semantic: { type: 'object', required: ['severity'] } } },
144
+ },
145
+ // With the default verdicts, `fail` takes the rule's severity.
146
+ {
147
+ if: { required: ['semantic'], properties: { semantic: { type: 'object', not: { required: ['verdicts'] } } } },
148
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema `if`/`then` keyword, not a thenable
149
+ then: {
150
+ properties: {
151
+ semantic: { type: 'object', properties: { severity: { type: 'object', not: { required: ['fail'] } } } },
152
+ },
153
+ },
154
+ },
155
+ // A rule with custom verdicts and no expression has no failure for the top-level severity to describe.
156
+ {
157
+ if: {
158
+ required: ['semantic'],
159
+ properties: { semantic: { type: 'object', required: ['verdicts'] } },
160
+ not: { required: ['expression'] },
161
+ },
162
+ // biome-ignore lint/suspicious/noThenProperty: JSON Schema `if`/`then` keyword, not a thenable
163
+ then: { not: { required: ['severity'] } },
164
+ },
165
+ ],
50
166
  };
51
- const RULE_REF_SCHEMA = {
167
+ const REF_SCHEMA = {
52
168
  type: 'object',
53
169
  properties: {
54
170
  $ref: { type: 'string', minLength: 1 },
@@ -56,6 +172,23 @@ const RULE_REF_SCHEMA = {
56
172
  required: ['$ref'],
57
173
  additionalProperties: false,
58
174
  };
175
+ const HIERARCHY_SCHEMA = {
176
+ type: 'object',
177
+ properties: {
178
+ name: { type: 'string', minLength: 1 },
179
+ override: { type: 'boolean' },
180
+ levels: {
181
+ type: 'array',
182
+ minItems: 1,
183
+ items: {
184
+ oneOf: [{ type: 'string', minLength: 1 }, HIERARCHY_LEVEL_SCHEMA],
185
+ },
186
+ },
187
+ allowSkipLevels: { type: 'boolean' },
188
+ },
189
+ required: ['levels'],
190
+ additionalProperties: false,
191
+ };
59
192
  const RELATIONSHIP_SCHEMA = {
60
193
  type: 'object',
61
194
  properties: {
@@ -63,53 +196,64 @@ const RELATIONSHIP_SCHEMA = {
63
196
  type: { type: 'string', minLength: 1 },
64
197
  ...EDGE_PROPS,
65
198
  ...EMBEDDING_PROPS,
199
+ override: { type: 'boolean' },
66
200
  },
67
201
  required: ['parent', 'type'],
68
202
  additionalProperties: false,
69
203
  };
70
- export const METADATA_SCHEMA = {
71
- type: 'object',
72
- properties: {
73
- hierarchy: {
204
+ /** An alias target: a type name, or `{ type, override: true }` to replace an imported alias. */
205
+ const ALIAS_SCHEMA = {
206
+ oneOf: [
207
+ { type: 'string', minLength: 1 },
208
+ {
74
209
  type: 'object',
75
210
  properties: {
76
- levels: {
77
- type: 'array',
78
- minItems: 1,
79
- items: {
80
- oneOf: [{ type: 'string', minLength: 1 }, HIERARCHY_LEVEL_SCHEMA],
81
- },
82
- },
83
- allowSkipLevels: { type: 'boolean' },
211
+ type: { type: 'string', minLength: 1 },
212
+ override: { type: 'boolean' },
84
213
  },
85
- required: ['levels'],
214
+ required: ['type'],
86
215
  additionalProperties: false,
87
216
  },
217
+ ],
218
+ };
219
+ export const METADATA_SCHEMA = {
220
+ type: 'object',
221
+ properties: {
222
+ // $ids of schemas whose metadata (and their imports' metadata) is merged into this schema's.
223
+ imports: {
224
+ type: 'array',
225
+ items: { type: 'string', minLength: 1 },
226
+ },
227
+ // Either declares this schema's hierarchy, or (root schema only) selects an imported one via $ref.
228
+ hierarchy: {
229
+ oneOf: [HIERARCHY_SCHEMA, REF_SCHEMA],
230
+ },
88
231
  relationships: {
89
232
  type: 'array',
90
233
  items: RELATIONSHIP_SCHEMA,
91
234
  },
92
235
  aliases: {
93
236
  type: 'object',
94
- additionalProperties: { type: 'string', minLength: 1 },
237
+ additionalProperties: ALIAS_SCHEMA,
95
238
  },
96
239
  rules: {
97
240
  type: 'array',
98
- items: {
99
- oneOf: [RULE_SCHEMA, RULE_REF_SCHEMA],
100
- },
241
+ items: RULE_SCHEMA,
101
242
  },
102
243
  },
103
244
  additionalProperties: false,
104
245
  };
105
- export const DIALECT_META_SCHEMA = {
106
- $schema: 'http://json-schema.org/draft-07/schema#',
107
- $id: SCHEMA_META_ID,
108
- title: 'structured-context schema dialect',
109
- description: 'Extends JSON Schema Draft-07 with top-level $metadata for hierarchy and rule metadata.',
110
- type: 'object',
111
- allOf: [{ $ref: 'http://json-schema.org/draft-07/schema#' }],
112
- properties: {
113
- $metadata: METADATA_SCHEMA,
114
- },
115
- };
246
+ /** The dialect meta-schema, published under `$id`. */
247
+ export function buildDialectMetaSchema(id) {
248
+ return {
249
+ $schema: JSON_SCHEMA_DIALECT,
250
+ $id: id,
251
+ title: 'structured-context schema dialect',
252
+ description: 'Extends JSON Schema 2020-12 with top-level $metadata for imports, hierarchy, relationships, aliases and rules.',
253
+ type: 'object',
254
+ allOf: [{ $ref: JSON_SCHEMA_DIALECT }],
255
+ properties: {
256
+ $metadata: METADATA_SCHEMA,
257
+ },
258
+ };
259
+ }
@@ -0,0 +1,12 @@
1
+ import type { Rule } from '../types';
2
+ export declare const RULE_FILTER_DIMENSIONS: readonly ["category", "severity", "type", "id"];
3
+ export type RuleFilterDimension = (typeof RULE_FILTER_DIMENSIONS)[number];
4
+ /** Narrows which rules are evaluated. Dimensions combine with AND; values within a dimension with OR. */
5
+ export type RuleFilter = Partial<Record<RuleFilterDimension, string[]>>;
6
+ /** Parse `dimension=value[,value]` specs (e.g. from repeated `--rule-filter` flags); repeats of a dimension merge. */
7
+ export declare function parseRuleFilter(specs: string[]): RuleFilter;
8
+ /**
9
+ * Keep the rules matching every dimension of the filter. A rule with no `type` never matches a `type` filter,
10
+ * and a rule with a verdict map matches a `severity` filter on any severity it can report.
11
+ */
12
+ export declare function filterRules(rules: Rule[], filter?: RuleFilter): Rule[];
@@ -0,0 +1,46 @@
1
+ import { ruleSeverities } from './rule-severity';
2
+ export const RULE_FILTER_DIMENSIONS = ['category', 'severity', 'type', 'id'];
3
+ /** Parse `dimension=value[,value]` specs (e.g. from repeated `--rule-filter` flags); repeats of a dimension merge. */
4
+ export function parseRuleFilter(specs) {
5
+ const filter = {};
6
+ for (const spec of specs) {
7
+ const eq = spec.indexOf('=');
8
+ const dimension = spec.slice(0, eq);
9
+ const values = spec
10
+ .slice(eq + 1)
11
+ .split(',')
12
+ .map((v) => v.trim())
13
+ .filter(Boolean);
14
+ if (eq < 0 || values.length === 0 || !RULE_FILTER_DIMENSIONS.includes(dimension)) {
15
+ throw new Error(`Invalid rule filter "${spec}". Use <${RULE_FILTER_DIMENSIONS.join('|')}>=<value>[,<value>...].`);
16
+ }
17
+ filter[dimension] = [...(filter[dimension] ?? []), ...values];
18
+ }
19
+ return filter;
20
+ }
21
+ function dimensionValues(rule, dimension) {
22
+ switch (dimension) {
23
+ case 'severity':
24
+ return ruleSeverities(rule);
25
+ case 'category':
26
+ return [rule.category];
27
+ case 'type':
28
+ return rule.type ? [rule.type] : [];
29
+ case 'id':
30
+ return [rule.id];
31
+ }
32
+ }
33
+ /**
34
+ * Keep the rules matching every dimension of the filter. A rule with no `type` never matches a `type` filter,
35
+ * and a rule with a verdict map matches a `severity` filter on any severity it can report.
36
+ */
37
+ export function filterRules(rules, filter) {
38
+ if (!filter)
39
+ return rules;
40
+ return rules.filter((rule) => RULE_FILTER_DIMENSIONS.every((dim) => {
41
+ const wanted = filter[dim];
42
+ if (!wanted)
43
+ return true;
44
+ return dimensionValues(rule, dim).some((value) => wanted.includes(value));
45
+ }));
46
+ }
@@ -0,0 +1,13 @@
1
+ import type { Rule, RuleCategory, RuleSeverity } from '../types';
2
+ import type { RuleSemantic } from './metadata-contract';
3
+ /** Default severity for each rule category. A rule's own `severity` field overrides this. */
4
+ export declare const DEFAULT_SEVERITY_BY_CATEGORY: Record<RuleCategory, RuleSeverity>;
5
+ /** The rule's semantic part as an object (`semantic: true` means `{}`), or undefined for a rule without one. */
6
+ export declare function ruleSemantic(rule: Rule): RuleSemantic | undefined;
7
+ /** Severity of a failed `expression` and of the default `fail` verdict: the rule's `severity`, else its category default. */
8
+ export declare function ruleSeverity(rule: Rule): RuleSeverity;
9
+ /**
10
+ * Every severity this rule can report: that of its failed `expression` (or default `fail` verdict), plus those
11
+ * its semantic verdict map sets. `ignore` entries report nothing. Most severe first.
12
+ */
13
+ export declare function ruleSeverities(rule: Rule): RuleSeverity[];
@@ -0,0 +1,33 @@
1
+ /** Default severity for each rule category. A rule's own `severity` field overrides this. */
2
+ export const DEFAULT_SEVERITY_BY_CATEGORY = {
3
+ validation: 'error',
4
+ coherence: 'warning',
5
+ workflow: 'warning',
6
+ 'best-practice': 'info',
7
+ };
8
+ const SEVERITY_ORDER = ['error', 'warning', 'info'];
9
+ /** The rule's semantic part as an object (`semantic: true` means `{}`), or undefined for a rule without one. */
10
+ export function ruleSemantic(rule) {
11
+ if (rule.semantic === undefined)
12
+ return undefined;
13
+ return rule.semantic === true ? {} : rule.semantic;
14
+ }
15
+ /** Severity of a failed `expression` and of the default `fail` verdict: the rule's `severity`, else its category default. */
16
+ export function ruleSeverity(rule) {
17
+ return rule.severity ?? DEFAULT_SEVERITY_BY_CATEGORY[rule.category];
18
+ }
19
+ /**
20
+ * Every severity this rule can report: that of its failed `expression` (or default `fail` verdict), plus those
21
+ * its semantic verdict map sets. `ignore` entries report nothing. Most severe first.
22
+ */
23
+ export function ruleSeverities(rule) {
24
+ const semantic = ruleSemantic(rule);
25
+ const found = new Set();
26
+ if (rule.expression !== undefined || (semantic && !semantic.verdicts))
27
+ found.add(ruleSeverity(rule));
28
+ for (const severity of Object.values(semantic?.severity ?? {})) {
29
+ if (severity !== 'ignore')
30
+ found.add(severity);
31
+ }
32
+ return SEVERITY_ORDER.filter((s) => found.has(s));
33
+ }
@@ -1,17 +1,23 @@
1
- import { type AnySchemaObject, type ValidateFunction } from 'ajv';
1
+ import type { AnySchemaObject, ValidateFunction } from 'ajv';
2
2
  import type { SchemaMetadata, SchemaWithMetadata } from '../types';
3
3
  export declare let bundledSchemasDir: string;
4
4
  /** Override the bundled schemas directory (e.g. when running in a bundled context). */
5
5
  export declare function setBundledSchemasDir(dir: string): void;
6
6
  export declare function readRawSchema(schemaPath: string): AnySchemaObject;
7
+ export declare const CORE_SCHEMA_PREFIX = "sctx://core/";
8
+ export type PluginSchemaSource = {
9
+ pluginName: string;
10
+ schemasDir: string;
11
+ };
7
12
  /**
8
- * Build the full two-layer registry for a schema path:
13
+ * Build the full multi-layer registry for a schema path:
9
14
  * - Layer 1: bundled schemas/ dir (partials only, as fallback)
10
- * - Layer 2: schema's own dir (partials + target file) — overrides layer 1
11
- * Does not throw on $id collision; layer 2 silently wins.
15
+ * - Layer 2: plugin schema dirs (partials + target file if schemaPath is in this plugin's schemasDir)
16
+ * - Layer 3: schema's own dir (partials + target file)
17
+ * Throws if a lower-precedence schema collides with a reserved $id or violates namespace rules.
12
18
  */
13
- export declare function buildFullRegistry(schemaPath: string): Map<string, AnySchemaObject>;
14
- export declare function createValidator(schemaPath: string): ValidateFunction;
19
+ export declare function buildFullRegistry(schemaPath: string, pluginSchemas?: PluginSchemaSource[]): Map<string, AnySchemaObject>;
20
+ export declare function createValidator(schemaPath: string, pluginSchemas?: PluginSchemaSource[]): ValidateFunction;
15
21
  export declare function resolveNodeType(type: string, typeAliases: Record<string, string> | undefined): string;
16
22
  export interface EntityInfo {
17
23
  type: string;
@@ -20,10 +26,10 @@ export interface EntityInfo {
20
26
  }
21
27
  export declare function extractEntityInfo(schema: SchemaWithMetadata, schemaRefRegistry: Map<string, AnySchemaObject>): EntityInfo[];
22
28
  export declare function extractSchemaTypeNames(schema: SchemaWithMetadata, schemaRefRegistry: Map<string, AnySchemaObject>): Set<string>;
23
- export declare function loadMetadata(schemaPath: string): SchemaMetadata;
29
+ export declare function loadMetadata(schemaPath: string, pluginSchemas?: PluginSchemaSource[]): SchemaMetadata;
24
30
  export interface LoadedSchema {
25
31
  schema: SchemaWithMetadata;
26
32
  schemaRefRegistry: Map<string, AnySchemaObject>;
27
33
  schemaValidator: ValidateFunction;
28
34
  }
29
- export declare function loadSchema(schemaPath: string): LoadedSchema;
35
+ export declare function loadSchema(schemaPath: string, pluginSchemas?: PluginSchemaSource[]): LoadedSchema;