yarramate 1.31.0 → 1.33.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/catalogues/core-enrichment.yaml +70 -0
- package/dist/adapters/likec4-export.d.ts +3 -0
- package/dist/adapters/likec4-export.js +4 -1
- package/dist/adapters/likec4-project-export.d.ts +10 -1
- package/dist/adapters/likec4-project-export.js +8 -3
- package/dist/adapters/likec4-project.d.ts +3 -0
- package/dist/adapters/likec4-project.js +4 -3
- package/dist/adapters/mcp-cli.js +17 -4
- package/dist/branding.d.ts +86 -0
- package/dist/branding.js +80 -0
- package/dist/brief.js +4 -1
- package/dist/cli-support.d.ts +1 -1
- package/dist/cli-support.js +1 -1
- package/dist/compiler.js +70 -50
- package/dist/export-command.js +30 -4
- package/dist/graph-projection.d.ts +12 -0
- package/dist/graph-projection.js +7 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/projection.d.ts +5 -0
- package/dist/projection.js +4 -0
- package/dist/relationship-reading.d.ts +12 -1
- package/dist/relationship-reading.js +28 -3
- package/dist/responsibility-kinds.d.ts +23 -0
- package/dist/responsibility-kinds.js +43 -0
- package/dist/responsibility.d.ts +99 -0
- package/dist/responsibility.js +239 -0
- package/dist/schema-validators.generated.js +37 -25
- package/dist/shipped-catalogue.generated.d.ts +1 -1
- package/dist/shipped-catalogue.generated.js +1 -1
- package/dist/shipped-profile.d.ts +21 -0
- package/dist/shipped-profile.js +33 -0
- package/dist/tools/export.d.ts +11 -0
- package/dist/tools/export.js +28 -1
- package/dist/tools/table.d.ts +32 -3
- package/dist/tools/table.js +96 -36
- package/dist/tools/workspace.d.ts +6 -0
- package/dist/tools-entry.d.ts +5 -2
- package/dist/tools-entry.js +5 -2
- package/dist/visual-app/assets/elk-worker.min-B0rP1gRk.js +22 -0
- package/dist/visual-app/assets/elk.bundled-NyuRbCog.js +24 -0
- package/dist/visual-app/assets/index-Bg4LA2rt.js +373 -0
- package/dist/visual-app/assets/index-DYTKTQsG.css +1 -0
- package/dist/visual-app/index.html +2 -2
- package/dist/visual-app-lib/editor.js +31979 -31096
- package/dist/visual-app-lib/styles.css +1 -1
- package/dist/visual-app-lib/types/branding.d.ts +86 -0
- package/dist/visual-app-lib/types/graph-projection.d.ts +12 -0
- package/dist/visual-app-lib/types/projection.d.ts +5 -0
- package/dist/visual-app-lib/types/relationship-reading.d.ts +12 -1
- package/dist/visual-app-lib/types/responsibility-kinds.d.ts +23 -0
- package/dist/visual-app-lib/types/shipped-catalogue.generated.d.ts +1 -1
- package/dist/visual-app-lib/types/shipped-profile.d.ts +21 -0
- package/dist/visual-app-lib/types/tools/workspace.d.ts +6 -0
- package/dist/visual-app-lib/types/visual-app/App.d.ts +4 -1
- package/dist/visual-app-lib/types/visual-app/elk-layout.d.ts +2 -0
- package/dist/visual-app-lib/types/visual-app/graph-canvas.d.ts +10 -1
- package/dist/visual-app-lib/types/visual-app/mount.d.ts +10 -0
- package/dist/visual-app-lib/types/visual-app/query-fields.d.ts +3 -2
- package/dist/visual-app-lib/types/visual-app/query-panel.d.ts +3 -1
- package/dist/visual-app-lib/types/visual-app/subject-form.d.ts +5 -0
- package/dist/visual-app-lib/types/visual-app/workspace-state.d.ts +4 -1
- package/dist/workbook-entry.d.ts +1 -0
- package/dist/workbook-entry.js +1 -0
- package/dist/workbook.d.ts +3 -2
- package/dist/workbook.js +19 -4
- package/docs/CONSUMING-YARRAMATE.md +56 -1
- package/package.json +10 -9
- package/schema/yarramate-projection.schema.json +4 -0
- package/schema/yarramate-responsibility.schema.json +123 -0
- package/schema/yarramate-visual-graph.schema.json +8 -0
- package/skills/yarramate-architecture/SKILL.md +1 -0
- package/dist/visual-app/assets/elk-worker.min-D8OVqK8T.js +0 -22
- package/dist/visual-app/assets/elk.bundled-JlCCXIin.js +0 -24
- package/dist/visual-app/assets/index-BSwETsaq.js +0 -373
- package/dist/visual-app/assets/index-CZSChZa6.css +0 -1
|
@@ -830,6 +830,76 @@ questions:
|
|
|
830
830
|
Add an owner reference to an accountable actor (evidence such as
|
|
831
831
|
CODEOWNERS may propose it; a human confirms accountability).
|
|
832
832
|
|
|
833
|
+
- id: responsible-missing
|
|
834
|
+
wave: business
|
|
835
|
+
since: "1.33"
|
|
836
|
+
scope: subject
|
|
837
|
+
subjects:
|
|
838
|
+
kinds:
|
|
839
|
+
- yarramate/core@0.1#businessService
|
|
840
|
+
- yarramate/core@0.1#applicationService
|
|
841
|
+
- yarramate/core@0.1#applicationComponent
|
|
842
|
+
- yarramate/core@0.1#capability
|
|
843
|
+
trigger:
|
|
844
|
+
- condition: missing-linkage
|
|
845
|
+
kinds:
|
|
846
|
+
- yarramate/policy@0.2#responsible
|
|
847
|
+
direction: incoming
|
|
848
|
+
counterpartKinds:
|
|
849
|
+
- yarramate/core@0.1#businessActor
|
|
850
|
+
- yarramate/core@0.1#businessRole
|
|
851
|
+
- yarramate/core@0.1#businessCollaboration
|
|
852
|
+
- yarramate/core@0.1#stakeholder
|
|
853
|
+
question: >-
|
|
854
|
+
Who is responsible for {subject.name}?
|
|
855
|
+
askPlain: >-
|
|
856
|
+
Who actually builds, runs or delivers "{subject.name}" day to day?
|
|
857
|
+
materiality: >-
|
|
858
|
+
Accountability says whose desk a failure lands on; responsibility says
|
|
859
|
+
whose hands are on it. A subject with nobody responsible has nobody to
|
|
860
|
+
hand the work to, and a RACI row with no R is a gap the matrix reports.
|
|
861
|
+
authority: either
|
|
862
|
+
resolution: >-
|
|
863
|
+
Add a `responsible` relationship from the actor, role or collaboration
|
|
864
|
+
that does the work to the subject (a support contract or CODEOWNERS may
|
|
865
|
+
propose it; a person confirms it).
|
|
866
|
+
- id: role-idle
|
|
867
|
+
wave: business
|
|
868
|
+
since: "1.33"
|
|
869
|
+
scope: subject
|
|
870
|
+
subjects:
|
|
871
|
+
kinds:
|
|
872
|
+
- yarramate/core@0.1#businessActor
|
|
873
|
+
- yarramate/core@0.1#businessRole
|
|
874
|
+
- yarramate/core@0.1#businessCollaboration
|
|
875
|
+
trigger:
|
|
876
|
+
- condition: missing-reference
|
|
877
|
+
predicate: yarramate/ownership/owner
|
|
878
|
+
direction: incoming
|
|
879
|
+
- condition: missing-relationship
|
|
880
|
+
kinds:
|
|
881
|
+
- yarramate/policy@0.2#responsible
|
|
882
|
+
- yarramate/policy@0.2#consulted
|
|
883
|
+
- yarramate/policy@0.2#informed
|
|
884
|
+
direction: outgoing
|
|
885
|
+
- condition: missing-relationship
|
|
886
|
+
kinds:
|
|
887
|
+
- yarramate/core@0.1#serving
|
|
888
|
+
direction: incoming
|
|
889
|
+
question: >-
|
|
890
|
+
What does {subject.name} answer for?
|
|
891
|
+
askPlain: >-
|
|
892
|
+
"{subject.name}" is in the model but owns nothing, is responsible for
|
|
893
|
+
nothing, and is neither consulted nor informed about anything. What is
|
|
894
|
+
their part, or should they go?
|
|
895
|
+
materiality: >-
|
|
896
|
+
A person with no letter is either missing the edges a delivery depends
|
|
897
|
+
on or a name that outlived its role. A served actor is a consumer, not
|
|
898
|
+
a responsibility holder, and is not asked.
|
|
899
|
+
authority: human
|
|
900
|
+
resolution: >-
|
|
901
|
+
Give the person a letter (an owner claim on what they answer for, or a
|
|
902
|
+
responsible, consulted or informed relationship) or retire the subject.
|
|
833
903
|
- id: actor-unassigned
|
|
834
904
|
wave: business
|
|
835
905
|
since: "0.1"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AdapterMapping } from '../adapter-mapping.js';
|
|
2
|
+
import { type Branding } from '../branding.js';
|
|
2
3
|
import type { StateComparison } from '../architecture-state.js';
|
|
3
4
|
import type { ProjectionResult } from '../projection.js';
|
|
4
5
|
import type { LikeC4KindMapping } from './likec4-kind-mapping.js';
|
|
@@ -21,6 +22,8 @@ export type LikeC4ExportResult = {
|
|
|
21
22
|
};
|
|
22
23
|
export interface LikeC4ExportOptions {
|
|
23
24
|
readonly comparison?: StateComparison;
|
|
25
|
+
/** The banner names the host's product (#546, ADR 0158); absent, the engine. */
|
|
26
|
+
readonly branding?: Branding;
|
|
24
27
|
/** Git-derived review overlay (ADR 0066): subjects new or changed in a
|
|
25
28
|
* ref range carry metadata and view styling; nothing is authored. */
|
|
26
29
|
readonly gitChange?: GitChangeOverlay;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { adapterMappingEntryLocation, adapterMappingLocation, } from '../adapter-mapping.js';
|
|
2
|
+
import { resolveBranding } from '../branding.js';
|
|
2
3
|
import { diagnosticOrder } from '../source-document.js';
|
|
3
4
|
const identifier = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
4
5
|
const valueFor = (claims, subject, predicate) => {
|
|
@@ -114,8 +115,10 @@ export function exportLikeC4(projection, mapping, kindMapping, options = {}) {
|
|
|
114
115
|
diagnostics: diagnostics.sort(diagnosticOrder),
|
|
115
116
|
};
|
|
116
117
|
}
|
|
118
|
+
const brand = resolveBranding(options.branding);
|
|
117
119
|
const lines = [
|
|
118
|
-
|
|
120
|
+
`// Generated by ${brand.productName}. Edit the native documents, not this file.`,
|
|
121
|
+
...(brand.vendorLine === null ? [] : [`// ${brand.vendorLine}`]),
|
|
119
122
|
'model {',
|
|
120
123
|
];
|
|
121
124
|
for (const concept of concepts) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { WorkspaceSource } from '../compiler.js';
|
|
2
|
+
import { type Branding } from '../branding.js';
|
|
2
3
|
import { type LikeC4PreparationDiagnostic } from './likec4-prepare.js';
|
|
3
4
|
import type { GitChangeOverlay } from './likec4-export.js';
|
|
4
5
|
import { type LikeC4ProjectDefinition, type PreparedLikeC4ProjectView } from './likec4-project.js';
|
|
@@ -26,6 +27,12 @@ export interface LikeC4ProjectExportInput {
|
|
|
26
27
|
readonly requireMappedRelationships: boolean;
|
|
27
28
|
/** The git-derived review overlay, when the CLI derived one. */
|
|
28
29
|
readonly gitChange?: GitChangeOverlay;
|
|
30
|
+
/**
|
|
31
|
+
* The host's branding (#546, ADR 0158): the model banner and the project
|
|
32
|
+
* name in `likec4.config.json`. The marker file and its digests are
|
|
33
|
+
* machinery and keep their names.
|
|
34
|
+
*/
|
|
35
|
+
readonly branding?: Branding;
|
|
29
36
|
}
|
|
30
37
|
export interface LikeC4ProjectExported {
|
|
31
38
|
readonly ok: true;
|
|
@@ -38,6 +45,8 @@ export interface LikeC4ProjectExported {
|
|
|
38
45
|
readonly kindMappingIdentity?: string;
|
|
39
46
|
/** Every source that fed the export, for the marker's input digests. */
|
|
40
47
|
readonly inputs: readonly WorkspaceSource[];
|
|
48
|
+
/** Echoed from the input so `generatedProjectFiles` names the project for it. */
|
|
49
|
+
readonly branding?: Branding;
|
|
41
50
|
}
|
|
42
51
|
export type LikeC4ProjectExportResult = LikeC4ProjectExported | {
|
|
43
52
|
readonly ok: false;
|
|
@@ -62,7 +71,7 @@ export interface GeneratedProjectOwnership {
|
|
|
62
71
|
}
|
|
63
72
|
export declare const ownershipOf: (exported: LikeC4ProjectExported) => GeneratedProjectOwnership;
|
|
64
73
|
export declare const inputDigestsOf: (inputs: readonly WorkspaceSource[]) => Readonly<Record<string, string>>;
|
|
65
|
-
export declare const projectNameOf: (projectIdentity: string) => string;
|
|
74
|
+
export declare const projectNameOf: (projectIdentity: string, branding?: Branding) => string;
|
|
66
75
|
/**
|
|
67
76
|
* The four files a generated project holds, exactly as the CLI writes them
|
|
68
77
|
* under its output directory: the config, the model, the specification the
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseDocument } from 'yaml';
|
|
2
|
+
import { brandSlug, resolveBranding } from '../branding.js';
|
|
2
3
|
import { sha256Hex } from '../digest.js';
|
|
3
4
|
import { LIKEC4_SPECIFICATION_SOURCE } from '../likec4-specification.generated.js';
|
|
4
5
|
import { locateSourcePath } from '../source-document.js';
|
|
@@ -165,7 +166,10 @@ export const exportLikeC4ProjectFromSources = (input) => {
|
|
|
165
166
|
}
|
|
166
167
|
renderedViewIds.add(renderedId);
|
|
167
168
|
}
|
|
168
|
-
const exported = exportLikeC4Project(definition, successfulViews,
|
|
169
|
+
const exported = exportLikeC4Project(definition, successfulViews, {
|
|
170
|
+
...(input.gitChange === undefined ? {} : { gitChange: input.gitChange }),
|
|
171
|
+
...(input.branding === undefined ? {} : { branding: input.branding }),
|
|
172
|
+
});
|
|
169
173
|
if (!exported.ok)
|
|
170
174
|
return { ok: false, diagnostics: exported.diagnostics };
|
|
171
175
|
const first = successfulViews[0];
|
|
@@ -182,6 +186,7 @@ export const exportLikeC4ProjectFromSources = (input) => {
|
|
|
182
186
|
kindMappingIdentity: `${first.prepared.kindMapping.id}@${first.prepared.kindMapping.version}`,
|
|
183
187
|
}),
|
|
184
188
|
inputs: [projectSource, ...sources, ...referencedSources.values()],
|
|
189
|
+
...(input.branding === undefined ? {} : { branding: input.branding }),
|
|
185
190
|
};
|
|
186
191
|
};
|
|
187
192
|
// ---------------------------------------------------------------------------
|
|
@@ -208,7 +213,7 @@ export const ownershipOf = (exported) => ({
|
|
|
208
213
|
export const inputDigestsOf = (inputs) => Object.fromEntries(inputs
|
|
209
214
|
.map(({ path, source }) => [path, sha256Hex(source)])
|
|
210
215
|
.sort(([left], [right]) => left.localeCompare(right)));
|
|
211
|
-
export const projectNameOf = (projectIdentity) =>
|
|
216
|
+
export const projectNameOf = (projectIdentity, branding) => `${brandSlug(resolveBranding(branding))}-${projectIdentity}`.replaceAll(/[^A-Za-z0-9_-]/g, '-');
|
|
212
217
|
/**
|
|
213
218
|
* The four files a generated project holds, exactly as the CLI writes them
|
|
214
219
|
* under its output directory: the config, the model, the specification the
|
|
@@ -218,7 +223,7 @@ export const projectNameOf = (projectIdentity) => `yarramate-${projectIdentity}`
|
|
|
218
223
|
export const generatedProjectFiles = (exported) => {
|
|
219
224
|
const configSource = `${JSON.stringify({
|
|
220
225
|
$schema: 'https://likec4.dev/schemas/config.json',
|
|
221
|
-
name: projectNameOf(exported.projectIdentity),
|
|
226
|
+
name: projectNameOf(exported.projectIdentity, exported.branding),
|
|
222
227
|
title: exported.project.title,
|
|
223
228
|
}, null, 2)}\n`;
|
|
224
229
|
const markerSource = `${JSON.stringify({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Branding } from '../branding.js';
|
|
1
2
|
import type { WorkspaceSource } from '../compiler.js';
|
|
2
3
|
import type { LikeC4PreparationResult } from './likec4-prepare.js';
|
|
3
4
|
import { type GitChangeOverlay, type LikeC4ExportResult } from './likec4-export.js';
|
|
@@ -59,5 +60,7 @@ export interface PreparedLikeC4ProjectView {
|
|
|
59
60
|
}
|
|
60
61
|
export interface LikeC4ProjectExportOptions {
|
|
61
62
|
readonly gitChange?: GitChangeOverlay;
|
|
63
|
+
/** Names the product in the model banner (#546, ADR 0158). */
|
|
64
|
+
readonly branding?: Branding;
|
|
62
65
|
}
|
|
63
66
|
export declare function exportLikeC4Project(project: LikeC4ProjectDefinition, views: readonly PreparedLikeC4ProjectView[], options?: LikeC4ProjectExportOptions): LikeC4ExportResult;
|
|
@@ -236,9 +236,10 @@ export function exportLikeC4Project(project, views, options = {}) {
|
|
|
236
236
|
if (first === undefined) {
|
|
237
237
|
throw new Error('LikeC4 project requires at least one view');
|
|
238
238
|
}
|
|
239
|
-
const model = exportLikeC4(unionProjection(project, views), first.prepared.subjectMapping, first.prepared.kindMapping,
|
|
240
|
-
? {}
|
|
241
|
-
: {
|
|
239
|
+
const model = exportLikeC4(unionProjection(project, views), first.prepared.subjectMapping, first.prepared.kindMapping, {
|
|
240
|
+
...(options.gitChange === undefined ? {} : { gitChange: options.gitChange }),
|
|
241
|
+
...(options.branding === undefined ? {} : { branding: options.branding }),
|
|
242
|
+
});
|
|
242
243
|
if (!model.ok)
|
|
243
244
|
return model;
|
|
244
245
|
const startToken = '\nviews {\n';
|
package/dist/adapters/mcp-cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { isMainModule, packageVersion, versionResult, } from '../cli-support.js'
|
|
|
7
7
|
import { runCli } from '../cli.js';
|
|
8
8
|
import { createFileSystemStore } from '../source-store.js';
|
|
9
9
|
import { loadWorkspaceManifest } from '../workspace.js';
|
|
10
|
-
import {
|
|
10
|
+
import { STDIO_PROPERTIES, TOOL_CATALOGUE, instructionsFor, runTool, } from '../tools/table.js';
|
|
11
11
|
/** The sentence the stdio rows add, because only here is there a `workspace` to name. */
|
|
12
12
|
const WORKSPACE_SENTENCE = 'Every tool takes the same optional `workspace`; omit it to use the workspace this server was started with, or .yarramate/workspace.yaml under its working directory.';
|
|
13
13
|
const CONVENTIONAL_WORKSPACE = join('.yarramate', 'workspace.yaml');
|
|
@@ -148,8 +148,8 @@ const runExport = (input, tool, root) => {
|
|
|
148
148
|
stderr: '',
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
|
-
// A text kind under `out`: markdown and graph are one file, rtm
|
|
152
|
-
// briefs a directory, as the CLI lays them out.
|
|
151
|
+
// A text kind under `out`: markdown and graph are one file, rtm,
|
|
152
|
+
// responsibility and briefs a directory, as the CLI lays them out.
|
|
153
153
|
if (kind === 'markdown' || kind === 'graph') {
|
|
154
154
|
mkdirSync(dirname(target), { recursive: true });
|
|
155
155
|
writeFileSync(target, outcome.text, 'utf8');
|
|
@@ -172,6 +172,19 @@ const runExport = (input, tool, root) => {
|
|
|
172
172
|
stderr: '',
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
|
+
if (kind === 'responsibility') {
|
|
176
|
+
const result = outcome.result;
|
|
177
|
+
mkdirSync(target, { recursive: true });
|
|
178
|
+
writeFileSync(join(target, 'RESPONSIBILITY.md'), outcome.text, 'utf8');
|
|
179
|
+
if (result !== undefined) {
|
|
180
|
+
writeFileSync(join(target, 'responsibility.json'), `${JSON.stringify(result.matrix, null, 2)}\n`, 'utf8');
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
exitCode: 0,
|
|
184
|
+
stdout: `Wrote RESPONSIBILITY.md and responsibility.json to ${out}\n`,
|
|
185
|
+
stderr: '',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
175
188
|
if (kind === 'briefs') {
|
|
176
189
|
const result = outcome.result;
|
|
177
190
|
mkdirSync(target, { recursive: true });
|
|
@@ -236,7 +249,7 @@ export const handleRequest = (request, context = { cwd: process.cwd(), workspace
|
|
|
236
249
|
protocolVersion: '2025-06-18',
|
|
237
250
|
capabilities: { tools: {} },
|
|
238
251
|
serverInfo: { name: 'yarramate', version: packageVersion },
|
|
239
|
-
instructions:
|
|
252
|
+
instructions: `${instructionsFor()} ${WORKSPACE_SENTENCE}`,
|
|
240
253
|
});
|
|
241
254
|
return;
|
|
242
255
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* White-labelling (#546, ADR 0158): one value, set once by a host, that
|
|
3
|
+
* names the product on every surface a consumer's users see - the editor
|
|
4
|
+
* shell, the tool list an agent reads, the workbook's cover sheet and the
|
|
5
|
+
* LikeC4 banner. Nothing else changes: record formats, diagnostic codes and
|
|
6
|
+
* the wire protocol are contracts, not branding, and stay `yarramate/...`
|
|
7
|
+
* and `YM...`. Absent, every surface reads exactly as it always has.
|
|
8
|
+
*
|
|
9
|
+
* Pure: no imports, so it sits under every entry (`yarramate/tools`,
|
|
10
|
+
* `yarramate/workbook`, `yarramate/visual-app`) without weight.
|
|
11
|
+
*/
|
|
12
|
+
export type BrandingLogo =
|
|
13
|
+
/** Inline markup the host wrote; rendered as the host's own SVG. */
|
|
14
|
+
{
|
|
15
|
+
readonly svg: string;
|
|
16
|
+
}
|
|
17
|
+
/** An address the page fetches; rendered as an image. */
|
|
18
|
+
| {
|
|
19
|
+
readonly url: string;
|
|
20
|
+
};
|
|
21
|
+
export interface Branding {
|
|
22
|
+
/** "ApertureX", "Halcyon Architecture". Required: a brand without a name is not one. */
|
|
23
|
+
readonly productName: string;
|
|
24
|
+
/**
|
|
25
|
+
* For tight chrome: beside the logo in the brand mark, and in the
|
|
26
|
+
* authority line ("Checked Halcyon model"). Defaults to `productName`.
|
|
27
|
+
* `null` draws the logo alone, for a wordmark that already says the name.
|
|
28
|
+
*/
|
|
29
|
+
readonly shortName?: string | null;
|
|
30
|
+
/** Beside the title in the editor shell. Nothing is drawn without one. */
|
|
31
|
+
readonly logo?: BrandingLogo;
|
|
32
|
+
/**
|
|
33
|
+
* One CSS colour for the chrome - the authority mark, the notices, the
|
|
34
|
+
* changeset controls - never the notation: what a node or an edge looks
|
|
35
|
+
* like is the style preset's, and a comparison's added/removed marks keep
|
|
36
|
+
* their own tokens.
|
|
37
|
+
*/
|
|
38
|
+
readonly accent?: string;
|
|
39
|
+
/** Where the brand mark links. Without it the mark is text, not a link. */
|
|
40
|
+
readonly docsUrl?: string;
|
|
41
|
+
/**
|
|
42
|
+
* The line under the product name, on the editor strip, the workbook's
|
|
43
|
+
* cover sheet and the LikeC4 banner. Unset: "Powered by yarramate". A
|
|
44
|
+
* string replaces it; `null` removes it, and with it every other mention
|
|
45
|
+
* of the engine those surfaces make.
|
|
46
|
+
*/
|
|
47
|
+
readonly vendorLine?: string | null;
|
|
48
|
+
/**
|
|
49
|
+
* The prefix of the tool names an agent reads: `acme` publishes
|
|
50
|
+
* `acme_design`, `acme_apply`, ... Default `yarramate`. An instruction
|
|
51
|
+
* written for `yarramate_design` will not find `acme_design`, so a host
|
|
52
|
+
* that re-prefixes owns its own agent instructions.
|
|
53
|
+
*/
|
|
54
|
+
readonly toolPrefix?: string;
|
|
55
|
+
}
|
|
56
|
+
/** `Branding` with every default applied, which is what the surfaces read. */
|
|
57
|
+
export interface ResolvedBranding {
|
|
58
|
+
readonly productName: string;
|
|
59
|
+
/** `null` when the mark is the logo alone; the authority line then says `productName`. */
|
|
60
|
+
readonly shortName: string | null;
|
|
61
|
+
readonly logo?: BrandingLogo;
|
|
62
|
+
readonly accent?: string;
|
|
63
|
+
readonly docsUrl?: string;
|
|
64
|
+
/** `null` when there is none to show. */
|
|
65
|
+
readonly vendorLine: string | null;
|
|
66
|
+
readonly toolPrefix: string;
|
|
67
|
+
/** False is the unbranded product: every surface as it was before #546. */
|
|
68
|
+
readonly branded: boolean;
|
|
69
|
+
}
|
|
70
|
+
export declare const YARRAMATE_PRODUCT_NAME = "YarraMate";
|
|
71
|
+
export declare const YARRAMATE_TOOL_PREFIX = "yarramate";
|
|
72
|
+
export declare const DEFAULT_VENDOR_LINE = "Powered by yarramate";
|
|
73
|
+
/**
|
|
74
|
+
* Applies the defaults. `undefined` is the unbranded product. A value with
|
|
75
|
+
* a blank `productName` or a `toolPrefix` no MCP client could publish is a
|
|
76
|
+
* host's configuration error and throws, at mount or serve time, rather
|
|
77
|
+
* than reaching a person as a blank name or an agent as a broken tool list.
|
|
78
|
+
*/
|
|
79
|
+
export declare const resolveBranding: (branding?: Branding) => ResolvedBranding;
|
|
80
|
+
/**
|
|
81
|
+
* The product name as an identifier segment: the LikeC4 project name is
|
|
82
|
+
* `<slug>-<project id>`, `yarramate-…` unbranded. Lower-case letters,
|
|
83
|
+
* digits and single hyphens; a name with nothing usable in it falls back
|
|
84
|
+
* to the engine's own slug rather than producing an empty segment.
|
|
85
|
+
*/
|
|
86
|
+
export declare const brandSlug: (branding: ResolvedBranding) => string;
|
package/dist/branding.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* White-labelling (#546, ADR 0158): one value, set once by a host, that
|
|
3
|
+
* names the product on every surface a consumer's users see - the editor
|
|
4
|
+
* shell, the tool list an agent reads, the workbook's cover sheet and the
|
|
5
|
+
* LikeC4 banner. Nothing else changes: record formats, diagnostic codes and
|
|
6
|
+
* the wire protocol are contracts, not branding, and stay `yarramate/...`
|
|
7
|
+
* and `YM...`. Absent, every surface reads exactly as it always has.
|
|
8
|
+
*
|
|
9
|
+
* Pure: no imports, so it sits under every entry (`yarramate/tools`,
|
|
10
|
+
* `yarramate/workbook`, `yarramate/visual-app`) without weight.
|
|
11
|
+
*/
|
|
12
|
+
export const YARRAMATE_PRODUCT_NAME = 'YarraMate';
|
|
13
|
+
export const YARRAMATE_TOOL_PREFIX = 'yarramate';
|
|
14
|
+
export const DEFAULT_VENDOR_LINE = 'Powered by yarramate';
|
|
15
|
+
/** What an MCP client accepts in a tool name, applied to the prefix alone. */
|
|
16
|
+
const TOOL_PREFIX = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
17
|
+
const UNBRANDED = {
|
|
18
|
+
productName: YARRAMATE_PRODUCT_NAME,
|
|
19
|
+
shortName: YARRAMATE_PRODUCT_NAME,
|
|
20
|
+
vendorLine: null,
|
|
21
|
+
toolPrefix: YARRAMATE_TOOL_PREFIX,
|
|
22
|
+
branded: false,
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Applies the defaults. `undefined` is the unbranded product. A value with
|
|
26
|
+
* a blank `productName` or a `toolPrefix` no MCP client could publish is a
|
|
27
|
+
* host's configuration error and throws, at mount or serve time, rather
|
|
28
|
+
* than reaching a person as a blank name or an agent as a broken tool list.
|
|
29
|
+
*/
|
|
30
|
+
export const resolveBranding = (branding) => {
|
|
31
|
+
if (branding === undefined)
|
|
32
|
+
return UNBRANDED;
|
|
33
|
+
const productName = branding.productName.trim();
|
|
34
|
+
if (productName === '') {
|
|
35
|
+
throw new TypeError('branding.productName must not be blank');
|
|
36
|
+
}
|
|
37
|
+
const toolPrefix = branding.toolPrefix ?? YARRAMATE_TOOL_PREFIX;
|
|
38
|
+
if (!TOOL_PREFIX.test(toolPrefix)) {
|
|
39
|
+
throw new TypeError(`branding.toolPrefix "${toolPrefix}" must be letters, digits and hyphens, starting with a letter or digit`);
|
|
40
|
+
}
|
|
41
|
+
const shortName = branding.shortName === null ? null : branding.shortName?.trim();
|
|
42
|
+
const vendorLine = branding.vendorLine === undefined
|
|
43
|
+
? DEFAULT_VENDOR_LINE
|
|
44
|
+
: branding.vendorLine === null || branding.vendorLine.trim() === ''
|
|
45
|
+
? null
|
|
46
|
+
: branding.vendorLine.trim();
|
|
47
|
+
return {
|
|
48
|
+
productName,
|
|
49
|
+
shortName: shortName === null
|
|
50
|
+
? null
|
|
51
|
+
: shortName === undefined || shortName === ''
|
|
52
|
+
? productName
|
|
53
|
+
: shortName,
|
|
54
|
+
...(branding.logo === undefined ? {} : { logo: branding.logo }),
|
|
55
|
+
...(branding.accent === undefined ? {} : { accent: branding.accent }),
|
|
56
|
+
...(branding.docsUrl === undefined ? {} : { docsUrl: branding.docsUrl }),
|
|
57
|
+
vendorLine,
|
|
58
|
+
toolPrefix,
|
|
59
|
+
branded: true,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The product name as an identifier segment: the LikeC4 project name is
|
|
64
|
+
* `<slug>-<project id>`, `yarramate-…` unbranded. Lower-case letters,
|
|
65
|
+
* digits and single hyphens; a name with nothing usable in it falls back
|
|
66
|
+
* to the engine's own slug rather than producing an empty segment.
|
|
67
|
+
*/
|
|
68
|
+
export const brandSlug = (branding) => {
|
|
69
|
+
if (!branding.branded)
|
|
70
|
+
return YARRAMATE_TOOL_PREFIX;
|
|
71
|
+
// Split on the runs and join what is left: linear, where a trim by
|
|
72
|
+
// `^-+|-+$` is polynomial on a name that is mostly hyphens (CodeQL
|
|
73
|
+
// js/polynomial-redos, the rule that bit #547's walker too).
|
|
74
|
+
const slug = (branding.shortName ?? branding.productName)
|
|
75
|
+
.toLowerCase()
|
|
76
|
+
.split(/[^a-z0-9]+/)
|
|
77
|
+
.filter((part) => part !== '')
|
|
78
|
+
.join('-');
|
|
79
|
+
return slug === '' ? YARRAMATE_TOOL_PREFIX : slug;
|
|
80
|
+
};
|
package/dist/brief.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { conceptKinds } from './profile.js';
|
|
2
|
-
import { RELATIONSHIP_READING, humanizeKind } from './relationship-reading.js';
|
|
2
|
+
import { EXTENSION_READING, RELATIONSHIP_READING, humanizeKind } from './relationship-reading.js';
|
|
3
3
|
const coreKindNames = new Map(conceptKinds.map(({ id, name }) => [id, name]));
|
|
4
4
|
const motivationKindIds = new Set(conceptKinds
|
|
5
5
|
.filter(({ layer }) => layer === 'motivation')
|
|
@@ -66,6 +66,9 @@ const relationshipPhrase = (coreKind, fallbackKind, mode, content) => {
|
|
|
66
66
|
if (coreKind === 'flow') {
|
|
67
67
|
return content === undefined ? 'flows to' : `sends ${content} to`;
|
|
68
68
|
}
|
|
69
|
+
const extension = EXTENSION_READING[fallbackKind];
|
|
70
|
+
if (extension !== undefined)
|
|
71
|
+
return extension;
|
|
69
72
|
const reading = coreKind === undefined ? undefined : RELATIONSHIP_READING[coreKind];
|
|
70
73
|
return reading ?? humanizeKind(fallbackKind);
|
|
71
74
|
};
|
package/dist/cli-support.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface CliResult {
|
|
|
7
7
|
export declare const isMainModule: (moduleUrl: string, entrypoint: string | undefined) => boolean;
|
|
8
8
|
export declare const packageVersion: string;
|
|
9
9
|
export declare const versionResult: (binary: string) => CliResult;
|
|
10
|
-
export declare const usage = "Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise \"<topic>\" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where \"<free text>\" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n";
|
|
10
|
+
export declare const usage = "Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise \"<topic>\" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where \"<free text>\" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export responsibility <projection.yaml> <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n";
|
|
11
11
|
export declare const diagnosticJson: (diagnostics: unknown) => string;
|
|
12
12
|
export declare const checkResultJson: (ok: boolean, diagnostics: unknown, counted?: {
|
|
13
13
|
readonly documents: number;
|
package/dist/cli-support.js
CHANGED
|
@@ -22,7 +22,7 @@ export const versionResult = (binary) => ({
|
|
|
22
22
|
stdout: `${binary} ${packageVersion}\n`,
|
|
23
23
|
stderr: '',
|
|
24
24
|
});
|
|
25
|
-
export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise "<topic>" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where "<free text>" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n';
|
|
25
|
+
export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise "<topic>" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where "<free text>" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export responsibility <projection.yaml> <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n';
|
|
26
26
|
export const diagnosticJson = (diagnostics) => `${JSON.stringify({
|
|
27
27
|
format: 'yarramate/diagnostic-result/v1',
|
|
28
28
|
diagnostics,
|
package/dist/compiler.js
CHANGED
|
@@ -3,7 +3,7 @@ import { conceptKinds, relationshipPolicies, } from './profile.js';
|
|
|
3
3
|
import { isCoreConceptKindId, matrixEndpointAspects, permittedRelationshipKinds as tablePermittedKinds, } from './relationship-matrix.js';
|
|
4
4
|
import { closestCandidate, describeSchemaViolation, } from './source-document.js';
|
|
5
5
|
import { ATTESTATION_PREDICATE_PREFIX, attestationClaimValue } from './graph-claims.js';
|
|
6
|
-
import {
|
|
6
|
+
import { shippedProfileOf } from './shipped-profile.js';
|
|
7
7
|
import { validateDocument, validateProfile, validatePattern } from './schema-validation.js';
|
|
8
8
|
const coreProfile = 'yarramate/core@0.1';
|
|
9
9
|
/**
|
|
@@ -371,58 +371,78 @@ function compileWorkspaceResolved(parsed) {
|
|
|
371
371
|
const identity = `${value.id}@${value.version}`;
|
|
372
372
|
pendingProfiles.push({ input, value, identity, positionFor });
|
|
373
373
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
374
|
+
// The shipped optional profiles (ADR 0095; policy@0.2 per ADR 0159). Each
|
|
375
|
+
// is injected when a document selects it or a profile extends it, and a
|
|
376
|
+
// shipped profile's own parent follows it in, so `extends:
|
|
377
|
+
// yarramate/policy@0.2` brings 0.1 along. A workspace file that declares
|
|
378
|
+
// the same identity wins; the shipped copy is not added beside it.
|
|
379
|
+
//
|
|
380
|
+
// This probe runs BEFORE the document gate that rejects a source whose
|
|
381
|
+
// schema check failed, so it has to hold its own precondition: a source
|
|
382
|
+
// that composes to anything but a mapping - an empty file, a comment-only
|
|
383
|
+
// one, a bare scalar - selects no profile at all. It used to read
|
|
384
|
+
// `.profile` through an `as` cast, which is what hid the null from the
|
|
385
|
+
// typechecker, and an empty document crashed the whole compile with a
|
|
386
|
+
// `TypeError` instead of the `YM201 must be object` its schema already
|
|
387
|
+
// produces. Every other consumer of a parsed entry checks its diagnostics
|
|
388
|
+
// first (the profile walk above, the pattern walk below); this one could
|
|
389
|
+
// not, because it runs before that gate exists, so it narrows instead.
|
|
390
|
+
const declaredIdentities = new Set(pendingProfiles.map(({ identity }) => identity));
|
|
391
|
+
const requestedIdentities = new Set();
|
|
392
|
+
for (const { entry } of documentInputs) {
|
|
393
|
+
const value = entry.value;
|
|
394
|
+
if (typeof value !== 'object' || value === null)
|
|
395
|
+
continue;
|
|
396
|
+
const profile = value.profile;
|
|
397
|
+
if (typeof profile === 'string')
|
|
398
|
+
requestedIdentities.add(profile);
|
|
399
|
+
}
|
|
400
|
+
for (const { value } of pendingProfiles)
|
|
401
|
+
requestedIdentities.add(value.extends);
|
|
402
|
+
const wantedShipped = [];
|
|
403
|
+
const want = (identity) => {
|
|
404
|
+
if (declaredIdentities.has(identity) || wantedShipped.includes(identity))
|
|
405
|
+
return;
|
|
406
|
+
const shipped = shippedProfileOf(identity);
|
|
407
|
+
if (shipped === undefined)
|
|
408
|
+
return;
|
|
409
|
+
wantedShipped.push(identity);
|
|
410
|
+
want(shipped.extends);
|
|
411
|
+
};
|
|
412
|
+
for (const identity of requestedIdentities)
|
|
413
|
+
want(identity);
|
|
414
|
+
for (const identity of wantedShipped) {
|
|
415
|
+
const shipped = shippedProfileOf(identity);
|
|
416
|
+
const input = {
|
|
417
|
+
path: `yarramate:profile:${identity}`,
|
|
418
|
+
source: shipped.source,
|
|
419
|
+
};
|
|
420
|
+
const { entry, fresh } = parseWorkspaceSource(input);
|
|
421
|
+
const value = entry.value;
|
|
422
|
+
if (entry.schemaDiagnostics.length > 0) {
|
|
423
|
+
profileDiagnostics.push(...entry.schemaDiagnostics);
|
|
424
|
+
}
|
|
425
|
+
else if (!validateProfile(value)) {
|
|
426
|
+
for (const error of validateProfile.errors ?? []) {
|
|
427
|
+
profileDiagnostics.push({
|
|
428
|
+
severity: 'error',
|
|
429
|
+
code: 'YM201',
|
|
430
|
+
message: `Profile schema violation: ${describeSchemaViolation(error)}`,
|
|
431
|
+
path: input.path,
|
|
432
|
+
pointer: error.instancePath || '/',
|
|
433
|
+
line: 1,
|
|
434
|
+
column: 1,
|
|
423
435
|
});
|
|
424
436
|
}
|
|
425
437
|
}
|
|
438
|
+
else {
|
|
439
|
+
pendingProfiles.push({
|
|
440
|
+
input,
|
|
441
|
+
value,
|
|
442
|
+
identity,
|
|
443
|
+
positionFor: positionReader(input.source, entry.positions, fresh),
|
|
444
|
+
});
|
|
445
|
+
}
|
|
426
446
|
}
|
|
427
447
|
let unresolvedProfiles = pendingProfiles.sort((left, right) => left.identity.localeCompare(right.identity) ||
|
|
428
448
|
left.input.path.localeCompare(right.input.path));
|