yarramate 0.10.0 → 0.11.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.
@@ -6,6 +6,7 @@ import { createHash, randomUUID } from 'node:crypto';
6
6
  import Ajv2020Module from 'ajv/dist/2020.js';
7
7
  import { isMap, isSeq, parseDocument } from 'yaml';
8
8
  import { isMainModule, resolveCliWorkspaceSources, versionResult, } from '../cli-support.js';
9
+ import { deriveChangedSubjects } from '../changed.js';
9
10
  import { compileWorkspace } from '../compiler.js';
10
11
  import { adapterMappingLocation, loadAdapterMapping, validateAdapterMapping, } from '../adapter-mapping.js';
11
12
  import { locateSourcePath } from '../source-document.js';
@@ -78,7 +79,7 @@ const usage = 'Usage:\n' +
78
79
  ' yarramate-likec4 check <likec4-project.yaml> [--json] <workspace-or-source...>\n' +
79
80
  ' yarramate-likec4 export <projection.yaml> <mapping.yaml> [--kinds <kind-mapping.yaml>] [--compare <from-state> <to-state>] <workspace-or-source...>\n' +
80
81
  ' yarramate-likec4 export-project [--check] <projection.yaml> <mapping.yaml> <output-dir> [--kinds <kind-mapping.yaml>] [--compare <from-state> <to-state>] <workspace-or-source...>\n' +
81
- ' yarramate-likec4 export-project [--check] <likec4-project.yaml> <output-dir> <workspace-or-source...>\n';
82
+ ' yarramate-likec4 export-project [--check] <likec4-project.yaml> <output-dir> [--changed <git-range>] <workspace-or-source...>\n';
82
83
  const diagnosticJson = (diagnostics) => `${JSON.stringify({
83
84
  format: 'yarramate/likec4-diagnostic-result/v1',
84
85
  diagnostics,
@@ -528,6 +529,7 @@ export function runLikeC4Cli(args, cwd = process.cwd()) {
528
529
  let invalidOptions = false;
529
530
  let kindMappingPath;
530
531
  let comparison;
532
+ let changedRange;
531
533
  const sourcePaths = [];
532
534
  for (let index = 0; index < sourceOptions.length; index += 1) {
533
535
  const option = sourceOptions[index];
@@ -549,6 +551,19 @@ export function runLikeC4Cli(args, cwd = process.cwd()) {
549
551
  }
550
552
  continue;
551
553
  }
554
+ if (option === '--changed') {
555
+ const value = sourceOptions[index + 1];
556
+ if (value === undefined ||
557
+ value.startsWith('-') ||
558
+ changedRange !== undefined) {
559
+ invalidOptions = true;
560
+ }
561
+ else {
562
+ changedRange = value;
563
+ index += 1;
564
+ }
565
+ continue;
566
+ }
552
567
  if (option === '--compare') {
553
568
  const from = sourceOptions[index + 1];
554
569
  const to = sourceOptions[index + 2];
@@ -581,6 +596,8 @@ export function runLikeC4Cli(args, cwd = process.cwd()) {
581
596
  (command === 'export-project' && outputDirectory === undefined) ||
582
597
  (projectDefinitionMode &&
583
598
  (kindMappingPath !== undefined || comparison !== undefined)) ||
599
+ (changedRange !== undefined &&
600
+ !(projectDefinitionMode && command === 'export-project')) ||
584
601
  invalidOptions ||
585
602
  sourcePaths.length === 0 ||
586
603
  sourcePaths.some((argument) => argument.startsWith('-'))) {
@@ -886,7 +903,32 @@ export function runLikeC4Cli(args, cwd = process.cwd()) {
886
903
  }
887
904
  renderedViewIds.add(renderedId);
888
905
  }
889
- const exported = exportLikeC4Project(loadedProject.document.value, successfulViews);
906
+ let gitChange;
907
+ if (changedRange !== undefined) {
908
+ const modelDocuments = sources.flatMap((candidate) => {
909
+ const parsed = parseDocument(candidate.source);
910
+ if (parsed.get('format') !== 'yarramate/v1')
911
+ return [];
912
+ const documentId = parsed.get('id');
913
+ return typeof documentId === 'string'
914
+ ? [{ ...candidate, documentId }]
915
+ : [];
916
+ });
917
+ const derived = deriveChangedSubjects(cwd, changedRange, modelDocuments);
918
+ if (!derived.ok) {
919
+ return { exitCode: 2, stdout: '', stderr: `${derived.message}\n` };
920
+ }
921
+ const all = [
922
+ ...derived.changed.concepts,
923
+ ...derived.changed.relationships,
924
+ ];
925
+ gitChange = {
926
+ range: derived.changed.range,
927
+ added: derived.changed.added,
928
+ modified: all.filter((id) => !derived.changed.added.includes(id)),
929
+ };
930
+ }
931
+ const exported = exportLikeC4Project(loadedProject.document.value, successfulViews, gitChange === undefined ? {} : { gitChange });
890
932
  if (!exported.ok) {
891
933
  return {
892
934
  exitCode: 1,
@@ -21,5 +21,13 @@ export type LikeC4ExportResult = {
21
21
  };
22
22
  export interface LikeC4ExportOptions {
23
23
  readonly comparison?: StateComparison;
24
+ /** Git-derived review overlay (ADR 0066): subjects new or changed in a
25
+ * ref range carry metadata and view styling; nothing is authored. */
26
+ readonly gitChange?: GitChangeOverlay;
27
+ }
28
+ export interface GitChangeOverlay {
29
+ readonly range: string;
30
+ readonly added: readonly string[];
31
+ readonly modified: readonly string[];
24
32
  }
25
33
  export declare function exportLikeC4(projection: ProjectionResult, mapping: AdapterMapping, kindMapping?: LikeC4KindMapping, options?: LikeC4ExportOptions): LikeC4ExportResult;
@@ -62,6 +62,13 @@ export function exportLikeC4(projection, mapping, kindMapping, options = {}) {
62
62
  const concepts = projection.subjects
63
63
  .filter(({ type }) => type === 'concept')
64
64
  .sort((left, right) => left.id.localeCompare(right.id));
65
+ const gitChangeOf = (id) => options.gitChange === undefined
66
+ ? undefined
67
+ : options.gitChange.added.includes(id)
68
+ ? 'new'
69
+ : options.gitChange.modified.includes(id)
70
+ ? 'changed'
71
+ : undefined;
65
72
  const comparisonChange = new Map(options.comparison === undefined
66
73
  ? []
67
74
  : [
@@ -121,6 +128,7 @@ export function exportLikeC4(projection, mapping, kindMapping, options = {}) {
121
128
  ['yarramateId', concept.id],
122
129
  ['yarramateKind', semanticKind],
123
130
  ['yarramateChange', comparisonChange.get(concept.id)],
131
+ ['yarramateGitChange', gitChangeOf(concept.id)],
124
132
  [
125
133
  'status',
126
134
  valueFor(projection.claims, concept.id, 'yarramate/lifecycle/status'),
@@ -168,6 +176,7 @@ export function exportLikeC4(projection, mapping, kindMapping, options = {}) {
168
176
  ['yarramateId', relationship.id],
169
177
  ['yarramateKind', structural.predicate],
170
178
  ['yarramateChange', comparisonChange.get(relationship.id)],
179
+ ['yarramateGitChange', gitChangeOf(relationship.id)],
171
180
  [
172
181
  'status',
173
182
  valueFor(projection.claims, relationship.id, 'yarramate/lifecycle/status'),
@@ -212,6 +221,18 @@ export function exportLikeC4(projection, mapping, kindMapping, options = {}) {
212
221
  return ` style ${external} { color red; border dashed }`;
213
222
  }
214
223
  return ` style ${external} { color gray }`;
224
+ })), ...(options.gitChange === undefined
225
+ ? []
226
+ : concepts.flatMap((concept) => {
227
+ const external = externalByNative.get(concept.id);
228
+ const change = gitChangeOf(concept.id);
229
+ if (change === 'new') {
230
+ return [` style ${external} { color green }`];
231
+ }
232
+ if (change === 'changed') {
233
+ return [` style ${external} { color amber }`];
234
+ }
235
+ return [];
215
236
  })), ' autoLayout LeftRight', ' }', '}', '');
216
237
  return { ok: true, source: lines.join('\n') };
217
238
  }
@@ -1,6 +1,6 @@
1
1
  import type { WorkspaceSource } from '../compiler.js';
2
2
  import type { LikeC4PreparationResult } from './likec4-prepare.js';
3
- import { type LikeC4ExportResult } from './likec4-export.js';
3
+ import { type GitChangeOverlay, type LikeC4ExportResult } from './likec4-export.js';
4
4
  export interface LikeC4ProjectDefinition {
5
5
  readonly format: 'yarramate/likec4-project/v1';
6
6
  readonly id: string;
@@ -55,4 +55,7 @@ export interface PreparedLikeC4ProjectView {
55
55
  };
56
56
  readonly deployment?: LikeC4Deployment;
57
57
  }
58
- export declare function exportLikeC4Project(project: LikeC4ProjectDefinition, views: readonly PreparedLikeC4ProjectView[]): LikeC4ExportResult;
58
+ export interface LikeC4ProjectExportOptions {
59
+ readonly gitChange?: GitChangeOverlay;
60
+ }
61
+ export declare function exportLikeC4Project(project: LikeC4ProjectDefinition, views: readonly PreparedLikeC4ProjectView[], options?: LikeC4ProjectExportOptions): LikeC4ExportResult;
@@ -28,7 +28,7 @@ const unionProjection = (project, views) => ({
28
28
  ...new Map(views.flatMap(({ prepared }) => prepared.projection.claims.map((claim) => [claim.id, claim]))).values(),
29
29
  ].sort((left, right) => left.id.localeCompare(right.id)),
30
30
  });
31
- const viewBody = ({ id, prepared, dynamic, deployment, }) => {
31
+ const viewBody = ({ id, prepared, dynamic, deployment, }, gitChange) => {
32
32
  const source = prepared.source;
33
33
  const startToken = '\nviews {\n';
34
34
  const start = source.indexOf(startToken);
@@ -117,10 +117,28 @@ const viewBody = ({ id, prepared, dynamic, deployment, }) => {
117
117
  ' }',
118
118
  ].join('\n');
119
119
  }
120
+ const overlayRules = gitChange === undefined
121
+ ? []
122
+ : prepared.projection.subjects
123
+ .filter(({ type }) => type === 'concept')
124
+ .flatMap(({ id: nativeId }) => {
125
+ const external = externalByNative.get(nativeId);
126
+ if (external === undefined)
127
+ return [];
128
+ if (gitChange.added.includes(nativeId)) {
129
+ return [` style ${external} { color green }`];
130
+ }
131
+ if (gitChange.modified.includes(nativeId)) {
132
+ return [` style ${external} { color amber }`];
133
+ }
134
+ return [];
135
+ })
136
+ .sort();
120
137
  const membershipRules = [
121
138
  includeRule,
122
139
  ' exclude * -> *',
123
140
  ...relationshipRules,
141
+ ...overlayRules,
124
142
  ].join('\n');
125
143
  return source
126
144
  .slice(start + startToken.length, end)
@@ -168,12 +186,48 @@ const deploymentBody = ({ deployment, prepared, }) => {
168
186
  '}',
169
187
  ].join('\n');
170
188
  };
171
- export function exportLikeC4Project(project, views) {
189
+ // The synthetic review view (ADR 0066): every changed subject with its
190
+ // highlight, and a description that doubles as the legend.
191
+ const reviewChangesView = (views, gitChange) => {
192
+ const externalByNative = new Map(views.flatMap((view) => view.prepared.subjectMapping.mappings
193
+ .filter(({ type }) => type === 'concept')
194
+ .map(({ native, external }) => [native, external])));
195
+ const changedConcepts = [
196
+ ...new Set([...gitChange.added, ...gitChange.modified].flatMap((nativeId) => {
197
+ const external = externalByNative.get(nativeId);
198
+ return external === undefined ? [] : [external];
199
+ })),
200
+ ].sort();
201
+ if (changedConcepts.length === 0)
202
+ return undefined;
203
+ const changedRelationships = [
204
+ ...new Set([...gitChange.added, ...gitChange.modified].filter((nativeId) => !externalByNative.has(nativeId))),
205
+ ].sort();
206
+ const styles = changedConcepts.map((external) => {
207
+ const nativeId = [...externalByNative.entries()].find(([, candidate]) => candidate === external)[0];
208
+ return gitChange.added.includes(nativeId)
209
+ ? ` style ${external} { color green }`
210
+ : ` style ${external} { color amber }`;
211
+ });
212
+ return [
213
+ ' view review-changes {',
214
+ ` title ${quote(`Review: ${gitChange.range}`)}`,
215
+ ` description ${quote(`Subjects touched in ${gitChange.range}. Legend: green = new, amber = changed; connected context unhighlighted. Derived from git - nothing here is authored (ADR 0066).`)}`,
216
+ ` include ${changedConcepts.join(', ')}`,
217
+ ...changedRelationships.map((id) => ` include * -> * where metadata.yarramateId is '${id}'`),
218
+ ...styles,
219
+ ' autoLayout LeftRight',
220
+ ' }',
221
+ ].join('\n');
222
+ };
223
+ export function exportLikeC4Project(project, views, options = {}) {
172
224
  const first = views[0];
173
225
  if (first === undefined) {
174
226
  throw new Error('LikeC4 project requires at least one view');
175
227
  }
176
- const model = exportLikeC4(unionProjection(project, views), first.prepared.subjectMapping, first.prepared.kindMapping);
228
+ const model = exportLikeC4(unionProjection(project, views), first.prepared.subjectMapping, first.prepared.kindMapping, options.gitChange === undefined
229
+ ? {}
230
+ : { gitChange: options.gitChange });
177
231
  if (!model.ok)
178
232
  return model;
179
233
  const startToken = '\nviews {\n';
@@ -182,9 +236,13 @@ export function exportLikeC4Project(project, views) {
182
236
  const rendered = deploymentBody(view);
183
237
  return rendered === undefined ? [] : [rendered];
184
238
  });
185
- const renderedViews = views.map(viewBody);
239
+ const renderedViews = views.map((view) => viewBody(view, options.gitChange));
240
+ const review = options.gitChange === undefined
241
+ ? undefined
242
+ : reviewChangesView(views, options.gitChange);
243
+ const allViews = review === undefined ? renderedViews : [...renderedViews, review];
186
244
  return {
187
245
  ok: true,
188
- source: `${model.source.slice(0, modelEnd)}${deployments.length === 0 ? '' : `\n${deployments.join('\n')}\n`}\nviews {\n${renderedViews.join('\n')}\n}\n`,
246
+ source: `${model.source.slice(0, modelEnd)}${deployments.length === 0 ? '' : `\n${deployments.join('\n')}\n`}\nviews {\n${allViews.join('\n')}\n}\n`,
189
247
  };
190
248
  }
package/dist/changed.d.ts CHANGED
@@ -2,6 +2,9 @@ export interface ChangedSubjects {
2
2
  readonly range: string;
3
3
  readonly concepts: readonly string[];
4
4
  readonly relationships: readonly string[];
5
+ /** Subjects whose entire declaration is new in the range (subset of
6
+ * concepts + relationships); the rest changed in place. */
7
+ readonly added: readonly string[];
5
8
  }
6
9
  export type ChangedResult = {
7
10
  readonly ok: true;
package/dist/changed.js CHANGED
@@ -52,16 +52,21 @@ const itemSpans = (source) => {
52
52
  }
53
53
  return spans;
54
54
  };
55
- // New-side line ranges from `git diff --unified=0`. A pure deletion has a
56
- // zero count; it still touches the position it collapsed onto.
57
55
  const changedLineRanges = (diff) => {
58
- const ranges = [];
59
- for (const match of diff.matchAll(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm)) {
60
- const start = Number(match[1]);
61
- const count = match[2] === undefined ? 1 : Number(match[2]);
62
- ranges.push(count === 0 ? [Math.max(start, 1), Math.max(start, 1)] : [start, start + count - 1]);
56
+ const touched = [];
57
+ const inserted = [];
58
+ for (const match of diff.matchAll(/^@@ -\d+(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/gm)) {
59
+ const oldCount = match[1] === undefined ? 1 : Number(match[1]);
60
+ const start = Number(match[2]);
61
+ const count = match[3] === undefined ? 1 : Number(match[3]);
62
+ const range = count === 0
63
+ ? [Math.max(start, 1), Math.max(start, 1)]
64
+ : [start, start + count - 1];
65
+ touched.push(range);
66
+ if (oldCount === 0 && count > 0)
67
+ inserted.push(range);
63
68
  }
64
- return ranges;
69
+ return { touched, inserted };
65
70
  };
66
71
  export function deriveChangedSubjects(cwd, range, documents) {
67
72
  const probe = spawnSync('git', ['-C', cwd, 'rev-parse', '--git-dir'], {
@@ -75,6 +80,7 @@ export function deriveChangedSubjects(cwd, range, documents) {
75
80
  }
76
81
  const concepts = new Set();
77
82
  const relationships = new Set();
83
+ const added = new Set();
78
84
  for (const document of documents) {
79
85
  const diffed = spawnSync('git', ['-C', cwd, 'diff', '--unified=0', range, '--', document.path], { encoding: 'utf8' });
80
86
  if (diffed.status !== 0) {
@@ -84,13 +90,13 @@ export function deriveChangedSubjects(cwd, range, documents) {
84
90
  };
85
91
  }
86
92
  const ranges = changedLineRanges(diffed.stdout ?? '');
87
- if (ranges.length === 0)
93
+ if (ranges.touched.length === 0)
88
94
  continue;
89
95
  const spans = itemSpans(document.source);
90
96
  for (const span of spans) {
91
97
  if (span.collection === 'states')
92
98
  continue;
93
- const touched = ranges.some(([from, to]) => from <= span.endLine && to >= span.startLine);
99
+ const touched = ranges.touched.some(([from, to]) => from <= span.endLine && to >= span.startLine);
94
100
  if (!touched)
95
101
  continue;
96
102
  const qualified = `${document.documentId}#${span.id}`;
@@ -98,6 +104,9 @@ export function deriveChangedSubjects(cwd, range, documents) {
98
104
  concepts.add(qualified);
99
105
  else
100
106
  relationships.add(qualified);
107
+ const whollyInserted = ranges.inserted.some(([from, to]) => from <= span.startLine && to >= span.endLine);
108
+ if (whollyInserted)
109
+ added.add(qualified);
101
110
  }
102
111
  }
103
112
  return {
@@ -106,6 +115,7 @@ export function deriveChangedSubjects(cwd, range, documents) {
106
115
  range,
107
116
  concepts: [...concepts].sort(),
108
117
  relationships: [...relationships].sort(),
118
+ added: [...added].sort(),
109
119
  },
110
120
  };
111
121
  }
@@ -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 <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--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>] [--catalogue <catalogue.yaml>] [--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>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\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 likec4 <likec4-project.yaml> <output-dir> <workspace.yaml>\n";
10
+ export declare const usage = "Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--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>] [--catalogue <catalogue.yaml>] [--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>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\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 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;
@@ -23,7 +23,7 @@ export const versionResult = (binary) => ({
23
23
  stdout: `${binary} ${packageVersion}\n`,
24
24
  stderr: '',
25
25
  });
26
- export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--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>] [--catalogue <catalogue.yaml>] [--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>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\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 likec4 <likec4-project.yaml> <output-dir> <workspace.yaml>\n';
26
+ export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--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>] [--catalogue <catalogue.yaml>] [--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>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\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 likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n';
27
27
  export const diagnosticJson = (diagnostics) => `${JSON.stringify({
28
28
  format: 'yarramate/diagnostic-result/v1',
29
29
  diagnostics,
@@ -91,6 +91,7 @@ export function runExportCommand(options, cwd) {
91
91
  parsed.json) {
92
92
  return { exitCode: 2, stdout: '', stderr: usage };
93
93
  }
94
+ const changedArguments = parsed.changed === undefined ? [] : ['--changed', parsed.changed];
94
95
  if (!existsSync(likec4AdapterEntry)) {
95
96
  return {
96
97
  exitCode: 2,
@@ -105,6 +106,7 @@ export function runExportCommand(options, cwd) {
105
106
  projectDefinition,
106
107
  outputDirectory,
107
108
  workspacePath,
109
+ ...changedArguments,
108
110
  ], { cwd, encoding: 'utf8' });
109
111
  const exitCode = delegated.status === 0 ? 0 : delegated.status === 1 ? 1 : 2;
110
112
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yarramate",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Tool-neutral semantic architecture engine and guided methodology",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -231,6 +231,13 @@
231
231
  "type": "string",
232
232
  "minLength": 1
233
233
  }
234
+ },
235
+ "added": {
236
+ "type": "array",
237
+ "items": {
238
+ "type": "string",
239
+ "minLength": 1
240
+ }
234
241
  }
235
242
  },
236
243
  "additionalProperties": false