yarramate 0.3.3 → 0.5.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/compiler.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import Ajv2020Module from 'ajv/dist/2020.js';
2
2
  import { LineCounter, parseDocument } from 'yaml';
3
3
  import { conceptKinds, relationshipPolicies, } from './profile.js';
4
+ import { closestCandidate, describeSchemaViolation, } from './source-document.js';
4
5
  import documentSchema from '../schema/yarramate-document.schema.json' with {
5
6
  type: 'json'
6
7
  };
@@ -53,6 +54,7 @@ function compileWorkspaceResolved(sources) {
53
54
  lineage: [`${coreProfile}#${policy.id}`],
54
55
  sourceAspects: policy.sourceAspects,
55
56
  targetAspects: policy.targetAspects,
57
+ repair: policy.repair,
56
58
  };
57
59
  coreRelationshipKinds.set(policy.id, resolved);
58
60
  relationshipKindByIdentity.set(resolved.identity, resolved);
@@ -112,7 +114,7 @@ function compileWorkspaceResolved(sources) {
112
114
  code: 'YM201',
113
115
  message: property
114
116
  ? `Property "${property}" is not allowed`
115
- : `Profile schema violation: ${error.message ?? error.keyword}`,
117
+ : `Profile schema violation: ${describeSchemaViolation(error)}`,
116
118
  path: input.path,
117
119
  pointer,
118
120
  line: position.line,
@@ -335,7 +337,7 @@ function compileWorkspaceResolved(sources) {
335
337
  code: 'YM201',
336
338
  message: property
337
339
  ? `Property "${property}" is not allowed`
338
- : `Document schema violation: ${error.message ?? error.keyword}`,
340
+ : `Document schema violation: ${describeSchemaViolation(error)}`,
339
341
  path: input.path,
340
342
  pointer,
341
343
  line: source.line,
@@ -536,7 +538,12 @@ function compileWorkspaceResolved(sources) {
536
538
  diagnostics.push({
537
539
  severity: 'error',
538
540
  code: 'YM401',
539
- message: `Unknown concept kind "${concept.kind}" in profile "${value.profile}"`,
541
+ message: `Unknown concept kind "${concept.kind}" in profile "${value.profile}"${(() => {
542
+ const suggestion = closestCandidate(concept.kind, selectedProfile.conceptKinds.keys());
543
+ return suggestion === undefined
544
+ ? ''
545
+ : `; did you mean "${suggestion}"?`;
546
+ })()}`,
540
547
  path: input.path,
541
548
  pointer,
542
549
  line: source.line,
@@ -742,7 +749,12 @@ function compileWorkspaceResolved(sources) {
742
749
  diagnostics.push({
743
750
  severity: 'error',
744
751
  code: 'YM402',
745
- message: `Unknown relationship kind "${relationship.kind}" in profile "${value.profile}"`,
752
+ message: `Unknown relationship kind "${relationship.kind}" in profile "${value.profile}"${(() => {
753
+ const suggestion = closestCandidate(relationship.kind, selectedProfile.relationshipKinds.keys());
754
+ return suggestion === undefined
755
+ ? ''
756
+ : `; did you mean "${suggestion}"?`;
757
+ })()}`,
746
758
  path: input.path,
747
759
  pointer,
748
760
  line: source.line,
@@ -787,7 +799,7 @@ function compileWorkspaceResolved(sources) {
787
799
  diagnostics.push({
788
800
  severity: 'error',
789
801
  code: 'YM404',
790
- message: `Relationship "${relationship.kind}" requires a ${endpoint} with aspect ${allowed.map((aspect) => `"${aspect}"`).join(' or ')}; "${reference}" has aspect "${kind.aspect}"`,
802
+ message: `Relationship "${relationship.kind}" requires a ${endpoint} with aspect ${allowed.map((aspect) => `"${aspect}"`).join(' or ')}; "${reference}" has aspect "${kind.aspect}"${policy.repair === undefined ? '' : `; ${policy.repair}`}`,
791
803
  path: input.path,
792
804
  pointer,
793
805
  line: source.line,
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { checkCoreContract, loadCoreContract, type CoreContract, type CoreContra
4
4
  export { compareArchitectureStates, type StateComparison, type StateComparisonIssue, type StateComparisonResult, } from './architecture-state.js';
5
5
  export { loadWorkspaceManifest, type ResolvedWorkspace, type WorkspaceManifest, type WorkspaceManifestResult, } from './workspace.js';
6
6
  export { evaluateEvidence, evaluateEvidenceWorkspace, loadEvidence, type EvidenceDocument, type EvidenceEvaluationResult, type EvidenceLoadResult, type EvidenceLocator, type EvidenceObservation, type EvidenceReport, type EvidenceResult, type EvidenceWorkspaceEvaluationResult, } from './evidence.js';
7
- export { reconcileEvidenceReports, type ReconciliationFinding, type ReconciliationReport, } from './reconciliation.js';
7
+ export { reconcileEvidenceReports, type AssertedRelationship, type ReconciliationFinding, type ReconciliationReport, } from './reconciliation.js';
8
8
  export type { CompilationResult, ContextualCompilationResult, Diagnostic, GraphClaim, GraphSource, SemanticGraph, ResolvedProfileContext, WorkspaceSource, } from './compiler.js';
9
9
  export { evaluateProjection, loadProjection, renderProjectionMarkdown, } from './projection.js';
10
10
  export { loadAdapterMapping, validateAdapterMapping, validateAdapterMappings, type AdapterMapping, type AdapterMappingLoadResult, type AdapterMappingValidationResult, type AdapterMappingsValidationResult, type AdapterSubjectMapping, } from './adapter-mapping.js';
@@ -0,0 +1,2 @@
1
+ import { type CliResult } from './cli-support.js';
2
+ export declare function runNewCommand(options: readonly string[], cwd: string): CliResult;
@@ -0,0 +1,111 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { humanDiagnostics, usage } from './cli-support.js';
4
+ import { loadProjection } from './projection.js';
5
+ const singleValueFlags = new Set([
6
+ '--id',
7
+ '--version',
8
+ '--title',
9
+ '--description',
10
+ '--relationships',
11
+ ]);
12
+ const repeatableFlags = new Set(['--document', '--subject', '--kind']);
13
+ const yamlText = (value) => /^[A-Za-z0-9][A-Za-z0-9 ._/@#-]*$/.test(value)
14
+ ? value
15
+ : JSON.stringify(value);
16
+ export function runNewCommand(options, cwd) {
17
+ const [family, target, ...flags] = options;
18
+ if (family !== 'projection' || target === undefined || target.startsWith('-')) {
19
+ return { exitCode: 2, stdout: '', stderr: usage };
20
+ }
21
+ const single = new Map();
22
+ const repeated = new Map();
23
+ for (let index = 0; index < flags.length; index += 2) {
24
+ const flag = flags[index];
25
+ const value = flags[index + 1];
26
+ if (flag === undefined ||
27
+ value === undefined ||
28
+ value.startsWith('--') ||
29
+ (!singleValueFlags.has(flag) && !repeatableFlags.has(flag))) {
30
+ return { exitCode: 2, stdout: '', stderr: usage };
31
+ }
32
+ if (singleValueFlags.has(flag)) {
33
+ if (single.has(flag)) {
34
+ return { exitCode: 2, stdout: '', stderr: usage };
35
+ }
36
+ single.set(flag, value);
37
+ }
38
+ else {
39
+ repeated.set(flag, [...(repeated.get(flag) ?? []), value]);
40
+ }
41
+ }
42
+ const id = single.get('--id');
43
+ if (id === undefined) {
44
+ return { exitCode: 2, stdout: '', stderr: usage };
45
+ }
46
+ const documents = repeated.get('--document');
47
+ const subjects = repeated.get('--subject');
48
+ const kinds = repeated.get('--kind');
49
+ if (documents === undefined && subjects === undefined && kinds === undefined) {
50
+ return {
51
+ exitCode: 2,
52
+ stdout: '',
53
+ stderr: 'new projection requires at least one selector: --document, --subject, or --kind\n',
54
+ };
55
+ }
56
+ const targetPath = resolve(cwd, target);
57
+ if (existsSync(targetPath)) {
58
+ return {
59
+ exitCode: 2,
60
+ stdout: '',
61
+ stderr: `${target} already exists; nothing was changed\n`,
62
+ };
63
+ }
64
+ const lines = [
65
+ 'format: yarramate/projection/v1',
66
+ `id: ${yamlText(id)}`,
67
+ `version: "${single.get('--version') ?? '1.0'}"`,
68
+ 'query:',
69
+ ];
70
+ const list = (key, values) => {
71
+ if (values === undefined)
72
+ return;
73
+ lines.push(` ${key}:`);
74
+ for (const value of values)
75
+ lines.push(` - ${yamlText(value)}`);
76
+ };
77
+ list('subjects', subjects);
78
+ list('documents', documents);
79
+ list('kinds', kinds);
80
+ const relationships = single.get('--relationships');
81
+ if (relationships !== undefined) {
82
+ lines.push(` relationships: ${yamlText(relationships)}`);
83
+ }
84
+ const title = single.get('--title');
85
+ const description = single.get('--description');
86
+ if (title !== undefined || description !== undefined) {
87
+ lines.push('presentation:');
88
+ if (title !== undefined)
89
+ lines.push(` title: ${yamlText(title)}`);
90
+ if (description !== undefined) {
91
+ lines.push(` description: ${yamlText(description)}`);
92
+ }
93
+ }
94
+ const source = `${lines.join('\n')}\n`;
95
+ const loaded = loadProjection({ path: target, source });
96
+ if (!loaded.ok) {
97
+ return {
98
+ exitCode: 1,
99
+ stdout: '',
100
+ stderr: humanDiagnostics(loaded.diagnostics),
101
+ };
102
+ }
103
+ mkdirSync(dirname(targetPath), { recursive: true });
104
+ writeFileSync(targetPath, source, 'utf8');
105
+ return {
106
+ exitCode: 0,
107
+ stdout: `Created ${target} (${loaded.projection.id}@${loaded.projection.version})\n` +
108
+ 'Include it in the workspace manifest projections list if no glob already covers it\n',
109
+ stderr: '',
110
+ };
111
+ }
package/dist/profile.d.ts CHANGED
@@ -21,6 +21,11 @@ export interface RelationshipPolicy {
21
21
  readonly intent: string;
22
22
  readonly sourceAspects?: readonly Aspect[];
23
23
  readonly targetAspects?: readonly Aspect[];
24
+ /**
25
+ * Repair hint appended to endpoint-aspect diagnostics (YM404). A remedy,
26
+ * never a correction: the compiler still rejects the input.
27
+ */
28
+ readonly repair?: string;
24
29
  }
25
30
  /**
26
31
  * Safe, intentionally broad semantic constraints. A future licensed
package/dist/profile.js CHANGED
@@ -137,6 +137,7 @@ export const relationshipPolicies = [
137
137
  id: 'assignment',
138
138
  intent: 'Allocate an active structure to behavior or responsibility',
139
139
  sourceAspects: ['active-structure'],
140
+ repair: 'assign from an active-structure element (an actor, component, or node), or use "association"',
140
141
  },
141
142
  { id: 'realization', intent: 'Fulfil a more abstract concept' },
142
143
  { id: 'serving', intent: 'Make behavior or an interface available' },
@@ -144,11 +145,13 @@ export const relationshipPolicies = [
144
145
  id: 'access',
145
146
  intent: 'Read, write, create, or use passive structure',
146
147
  targetAspects: ['passive-structure'],
148
+ repair: 'point "access" at passive structure (a business object, data object, or artifact), or use "association"',
147
149
  },
148
150
  {
149
151
  id: 'influence',
150
152
  intent: 'Affect a motivation concept',
151
153
  targetAspects: ['motivation'],
154
+ repair: 'point "influence" at a motivation concept (a goal, requirement, or principle), or use "association"',
152
155
  },
153
156
  { id: 'association', intent: 'Relevant connection with no stronger meaning' },
154
157
  {
@@ -156,6 +159,7 @@ export const relationshipPolicies = [
156
159
  intent: 'Express temporal or causal precedence',
157
160
  sourceAspects: ['behavior'],
158
161
  targetAspects: ['behavior'],
162
+ repair: 'use "flow" between active-structure elements, or introduce a behavior concept and "assignment"',
159
163
  },
160
164
  { id: 'flow', intent: 'Transfer information, value, goods, or material' },
161
165
  { id: 'specialization', intent: 'Express a more specific form' },
@@ -40,3 +40,4 @@ export type ProjectionLoadResult = {
40
40
  export declare function loadProjection(source: WorkspaceSource): ProjectionLoadResult;
41
41
  export declare function evaluateProjection(graph: SemanticGraph, projection: ProjectionDefinition, profileContext?: ResolvedProfileContext): ProjectionResult;
42
42
  export declare function renderProjectionMarkdown(result: ProjectionResult): string;
43
+ export declare function renderBudgetedContext(result: ProjectionResult, budgetTokens: number): string;
@@ -181,3 +181,109 @@ export function renderProjectionMarkdown(result) {
181
181
  }
182
182
  return `${lines.join('\n')}\n`;
183
183
  }
184
+ const estimateTokens = (text) => Math.ceil(text.length / 4);
185
+ export function renderBudgetedContext(result, budgetTokens) {
186
+ const concepts = result.subjects.filter(({ type }) => type === 'concept');
187
+ const relationships = result.subjects.filter(({ type }) => type === 'relationship');
188
+ const title = result.presentation?.title ?? result.projection;
189
+ const header = [
190
+ `context ${result.projection} — ${title}`,
191
+ `subjects: ${concepts.length} concepts, ${relationships.length} relationships`,
192
+ ];
193
+ const subjectLines = [];
194
+ for (const concept of concepts) {
195
+ const name = claimValue(result.claims, concept.id, 'yarramate/concept/name');
196
+ const kind = claimValue(result.claims, concept.id, 'yarramate/concept/kind') ??
197
+ 'unknown';
198
+ const status = claimValue(result.claims, concept.id, 'yarramate/lifecycle/status');
199
+ subjectLines.push(`- ${concept.id} [${kind.split('#')[1] ?? kind}]` +
200
+ `${name === undefined ? '' : ` ${name}`}` +
201
+ `${status === undefined ? '' : ` (${status})`}`);
202
+ }
203
+ const relationshipLines = [];
204
+ for (const relationship of relationships) {
205
+ const claim = result.claims.find(({ id, object }) => id === relationship.id && 'ref' in object);
206
+ if (claim !== undefined && 'ref' in claim.object) {
207
+ const kind = claim.predicate.split('#')[1] ?? claim.predicate;
208
+ relationshipLines.push(`- ${claim.subject} -${kind}-> ${claim.object.ref}`);
209
+ }
210
+ }
211
+ const descriptionLines = [];
212
+ for (const subject of result.subjects) {
213
+ const description = claimValue(result.claims, subject.id, 'yarramate/concept/description') ??
214
+ claimValue(result.claims, subject.id, 'yarramate/relationship/description');
215
+ if (description !== undefined) {
216
+ descriptionLines.push(`- ${subject.id}: ${description}`);
217
+ }
218
+ }
219
+ const detailPredicates = new Set([
220
+ 'yarramate/ownership/owner',
221
+ 'yarramate/constraint/requires',
222
+ 'yarramate/reference/refers-to',
223
+ 'yarramate/access/mode',
224
+ 'yarramate/state/present-in',
225
+ ]);
226
+ const detailLines = [];
227
+ for (const claim of result.claims) {
228
+ if (!detailPredicates.has(claim.predicate))
229
+ continue;
230
+ const value = 'ref' in claim.object ? claim.object.ref : claim.object.value;
231
+ const predicate = claim.predicate.split('/').pop() ?? claim.predicate;
232
+ detailLines.push(`- ${claim.subject} ${predicate}: ${value}`);
233
+ }
234
+ // Ranked ladder: the two header lines always render; every other line —
235
+ // including the subject skeleton — competes for the remaining budget in
236
+ // priority order, and anything dropped is always announced rather than
237
+ // silently omitted.
238
+ const sections = [
239
+ { heading: 'relationships:', lines: relationshipLines },
240
+ { heading: 'descriptions:', lines: descriptionLines },
241
+ { heading: 'details:', lines: detailLines },
242
+ ];
243
+ const rendered = [...header];
244
+ const omitted = [];
245
+ let spent = estimateTokens(rendered.join('\n'));
246
+ let droppedSubjects = 0;
247
+ for (const line of subjectLines) {
248
+ const cost = estimateTokens(line);
249
+ if (spent + cost > budgetTokens) {
250
+ droppedSubjects += 1;
251
+ continue;
252
+ }
253
+ rendered.push(line);
254
+ spent += cost;
255
+ }
256
+ if (droppedSubjects > 0) {
257
+ omitted.push(`subjects ${droppedSubjects} omitted`);
258
+ }
259
+ for (const section of sections) {
260
+ if (section.lines.length === 0)
261
+ continue;
262
+ const kept = [section.heading];
263
+ let sectionSpent = estimateTokens(section.heading);
264
+ let dropped = 0;
265
+ for (const line of section.lines) {
266
+ const cost = estimateTokens(line);
267
+ if (spent + sectionSpent + cost > budgetTokens) {
268
+ dropped += 1;
269
+ continue;
270
+ }
271
+ kept.push(line);
272
+ sectionSpent += cost;
273
+ }
274
+ if (kept.length > 1) {
275
+ rendered.push('', ...kept);
276
+ spent += sectionSpent;
277
+ }
278
+ else {
279
+ dropped = section.lines.length;
280
+ }
281
+ if (dropped > 0) {
282
+ omitted.push(`${section.heading.replace(':', '')} ${dropped} omitted`);
283
+ }
284
+ }
285
+ if (omitted.length > 0) {
286
+ rendered.push('', `[budget ${budgetTokens}: ${omitted.join('; ')} — raise --budget or use JSON mode for the complete slice]`);
287
+ }
288
+ return `${rendered.join('\n')}\n`;
289
+ }
@@ -1,9 +1,17 @@
1
+ import type { SemanticGraph } from './compiler.js';
1
2
  import type { EvidenceLocator, EvidenceReport, EvidenceResult } from './evidence.js';
3
+ export interface AssertedRelationship {
4
+ readonly from: string;
5
+ readonly to: string;
6
+ readonly kind: string;
7
+ readonly name?: string;
8
+ }
2
9
  export interface ReconciliationFinding {
3
10
  readonly target: {
4
11
  readonly type: 'subject' | 'claim';
5
12
  readonly id: string;
6
13
  };
14
+ readonly asserted?: AssertedRelationship;
7
15
  readonly result: Exclude<EvidenceResult, 'confirmed'>;
8
16
  readonly provider: string;
9
17
  readonly evidenceDocument: string;
@@ -23,4 +31,4 @@ export interface ReconciliationReport {
23
31
  };
24
32
  readonly findings: readonly ReconciliationFinding[];
25
33
  }
26
- export declare function reconcileEvidenceReports(workspace: string, reports: readonly EvidenceReport[]): ReconciliationReport;
34
+ export declare function reconcileEvidenceReports(workspace: string, reports: readonly EvidenceReport[], graph?: SemanticGraph): ReconciliationReport;
@@ -1,4 +1,32 @@
1
- export function reconcileEvidenceReports(workspace, reports) {
1
+ const assertedRelationshipsByClaim = (graph) => {
2
+ const asserted = new Map();
3
+ if (graph === undefined)
4
+ return asserted;
5
+ const relationshipIds = new Set(graph.subjects
6
+ .filter(({ type }) => type === 'relationship')
7
+ .map(({ id }) => id));
8
+ const names = new Map();
9
+ for (const claim of graph.claims) {
10
+ if (claim.predicate === 'yarramate/relationship/name' &&
11
+ 'value' in claim.object) {
12
+ names.set(claim.subject, claim.object.value);
13
+ }
14
+ }
15
+ for (const claim of graph.claims) {
16
+ if (!relationshipIds.has(claim.id) || !('ref' in claim.object))
17
+ continue;
18
+ const name = names.get(claim.id);
19
+ asserted.set(claim.id, {
20
+ from: claim.subject,
21
+ to: claim.object.ref,
22
+ kind: claim.predicate,
23
+ ...(name === undefined ? {} : { name }),
24
+ });
25
+ }
26
+ return asserted;
27
+ };
28
+ export function reconcileEvidenceReports(workspace, reports, graph) {
29
+ const assertedByClaim = assertedRelationshipsByClaim(graph);
2
30
  const summary = {
3
31
  evidenceDocuments: reports.length,
4
32
  observations: 0,
@@ -22,10 +50,13 @@ export function reconcileEvidenceReports(workspace, reports) {
22
50
  else {
23
51
  summary[observation.result] += 1;
24
52
  }
53
+ const target = 'subject' in observation
54
+ ? { type: 'subject', id: observation.subject }
55
+ : { type: 'claim', id: observation.claim };
56
+ const asserted = target.type === 'claim' ? assertedByClaim.get(target.id) : undefined;
25
57
  findings.push({
26
- target: 'subject' in observation
27
- ? { type: 'subject', id: observation.subject }
28
- : { type: 'claim', id: observation.claim },
58
+ target,
59
+ ...(asserted === undefined ? {} : { asserted }),
29
60
  result: observation.result,
30
61
  provider: report.provider,
31
62
  evidenceDocument: report.evidence,
@@ -1,4 +1,4 @@
1
- import type { ValidateFunction } from 'ajv';
1
+ import type { ErrorObject, ValidateFunction } from 'ajv';
2
2
  import { LineCounter, parseDocument } from 'yaml';
3
3
  import type { Diagnostic, WorkspaceSource } from './compiler.js';
4
4
  export interface SourceLocation {
@@ -20,5 +20,7 @@ export type SourceDocumentResult<T> = {
20
20
  readonly diagnostics: readonly Diagnostic[];
21
21
  };
22
22
  export declare const diagnosticOrder: (left: Diagnostic, right: Diagnostic) => number;
23
+ export declare const describeSchemaViolation: (error: Pick<ErrorObject, "keyword" | "message" | "params">) => string;
24
+ export declare const closestCandidate: (value: string, candidates: Iterable<string>) => string | undefined;
23
25
  export declare function locateSourcePath(sourcePath: string, yaml: ReturnType<typeof parseDocument>, lineCounter: LineCounter, yamlPath: readonly (string | number)[], pointer: string): SourceLocation;
24
26
  export declare function loadSourceDocument<T>(source: WorkspaceSource, validate: ValidateFunction, schemaLabel: string): SourceDocumentResult<T>;
@@ -4,6 +4,48 @@ export const diagnosticOrder = (left, right) => left.path.localeCompare(right.pa
4
4
  left.column - right.column ||
5
5
  left.code.localeCompare(right.code) ||
6
6
  left.message.localeCompare(right.message);
7
+ export const describeSchemaViolation = (error) => {
8
+ const base = error.message ?? error.keyword;
9
+ if (error.keyword === 'const') {
10
+ return `${base}: expected ${JSON.stringify(error.params.allowedValue)}`;
11
+ }
12
+ if (error.keyword === 'enum' &&
13
+ Array.isArray(error.params.allowedValues)) {
14
+ const allowed = error.params.allowedValues;
15
+ const shown = allowed
16
+ .slice(0, 8)
17
+ .map((value) => JSON.stringify(value))
18
+ .join(', ');
19
+ return `${base}: ${shown}${allowed.length > 8 ? ', …' : ''}`;
20
+ }
21
+ return base;
22
+ };
23
+ const editDistance = (left, right) => {
24
+ const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
25
+ for (let i = 1; i <= left.length; i += 1) {
26
+ let diagonal = previous[0];
27
+ previous[0] = i;
28
+ for (let j = 1; j <= right.length; j += 1) {
29
+ const above = previous[j];
30
+ previous[j] = Math.min(above + 1, previous[j - 1] + 1, diagonal + (left[i - 1] === right[j - 1] ? 0 : 1));
31
+ diagonal = above;
32
+ }
33
+ }
34
+ return previous[right.length];
35
+ };
36
+ export const closestCandidate = (value, candidates) => {
37
+ const threshold = Math.max(2, Math.floor(value.length / 4));
38
+ let best;
39
+ let bestDistance = threshold + 1;
40
+ for (const candidate of [...candidates].sort()) {
41
+ const distance = editDistance(value.toLowerCase(), candidate.toLowerCase());
42
+ if (distance < bestDistance) {
43
+ best = candidate;
44
+ bestDistance = distance;
45
+ }
46
+ }
47
+ return best;
48
+ };
7
49
  export function locateSourcePath(sourcePath, yaml, lineCounter, yamlPath, pointer) {
8
50
  const node = yaml.getIn(yamlPath, true);
9
51
  const offset = typeof node === 'object' &&
@@ -62,7 +104,7 @@ export function loadSourceDocument(source, validate, schemaLabel) {
62
104
  code: 'YM201',
63
105
  message: property
64
106
  ? `Property "${property}" is not allowed`
65
- : `${schemaLabel} schema violation: ${error.message ?? error.keyword}`,
107
+ : `${schemaLabel} schema violation: ${describeSchemaViolation(error)}`,
66
108
  ...location,
67
109
  };
68
110
  })
@@ -0,0 +1,2 @@
1
+ import { type CliResult } from './cli-support.js';
2
+ export declare function runStatusCommand(options: readonly string[], cwd: string): CliResult;