yarramate 0.6.0 → 0.7.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/README.md +39 -12
- package/catalogues/core-enrichment.yaml +700 -0
- package/dist/adapters/mcp-cli.js +55 -49
- package/dist/apply-command.d.ts +2 -0
- package/dist/apply-command.js +199 -0
- package/dist/{new-command.d.ts → ask-command.d.ts} +1 -1
- package/dist/ask-command.js +729 -0
- package/dist/brief.d.ts +3 -0
- package/dist/brief.js +235 -0
- package/dist/cli-support.d.ts +1 -1
- package/dist/cli-support.js +1 -1
- package/dist/cli.js +22 -590
- package/dist/compiler.js +13 -0
- package/dist/core-contract.d.ts +1 -1
- package/dist/{status-command.d.ts → design-command.d.ts} +1 -1
- package/dist/design-command.js +218 -0
- package/dist/export-command.d.ts +2 -0
- package/dist/export-command.js +228 -0
- package/dist/interrogate-command.d.ts +104 -0
- package/dist/interrogate-command.js +268 -0
- package/dist/next-command.d.ts +5 -8
- package/dist/next-command.js +106 -211
- package/docs/CONSUMING-YARRAMATE.md +28 -21
- package/package.json +13 -11
- package/schema/yarramate-apply-result.schema.json +32 -0
- package/schema/yarramate-ask-result.schema.json +391 -0
- package/schema/yarramate-core-contract.schema.json +5 -11
- package/schema/yarramate-design-step.schema.json +152 -0
- package/schema/yarramate-document.schema.json +76 -9
- package/schema/yarramate-interrogation-report.schema.json +89 -0
- package/schema/yarramate-operations.schema.json +303 -0
- package/schema/yarramate-question-catalogue.schema.json +431 -0
- package/skills/yarramate-architecture/SKILL.md +42 -17
- package/skills/yarramate-architecture/references/native-authoring.md +73 -17
- package/dist/new-command.js +0 -111
- package/dist/status-command.js +0 -174
- package/schema/yarramate-next-result.schema.json +0 -85
- package/schema/yarramate-status-result.schema.json +0 -278
package/dist/cli.js
CHANGED
|
@@ -1,244 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
|
|
3
3
|
import { dirname, relative, resolve } from 'node:path';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { serializeSemanticGraph } from './graph.js';
|
|
8
|
-
import { diagnosticJson, humanDiagnostics, isMainModule, resolveCliWorkspaceSources, usage, versionResult, } from './cli-support.js';
|
|
4
|
+
import { compileWorkspace } from './compiler.js';
|
|
5
|
+
import { diagnosticJson, isMainModule, usage, versionResult, } from './cli-support.js';
|
|
6
|
+
import { runAskCommand } from './ask-command.js';
|
|
9
7
|
import { runCheckCommand } from './check-command.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
8
|
+
import { runExportCommand } from './export-command.js';
|
|
9
|
+
import { runApplyCommand } from './apply-command.js';
|
|
10
|
+
import { runDesignCommand } from './design-command.js';
|
|
11
|
+
import { evaluateEvidenceWorkspace, loadEvidence, } from './evidence.js';
|
|
14
12
|
import { reconcileEvidenceReports } from './reconciliation.js';
|
|
15
13
|
import { loadWorkspaceManifest } from './workspace.js';
|
|
16
|
-
import { evaluateProjection, loadProjection, renderBudgetedContext, renderProjectionMarkdown, } from './projection.js';
|
|
17
|
-
const extractBudget = (options) => {
|
|
18
|
-
const rest = [];
|
|
19
|
-
let budget;
|
|
20
|
-
for (let index = 0; index < options.length; index += 1) {
|
|
21
|
-
const option = options[index];
|
|
22
|
-
if (option === '--budget') {
|
|
23
|
-
const value = options[index + 1];
|
|
24
|
-
if (value === undefined ||
|
|
25
|
-
budget !== undefined ||
|
|
26
|
-
!/^[1-9][0-9]*$/.test(value)) {
|
|
27
|
-
return { ok: false };
|
|
28
|
-
}
|
|
29
|
-
budget = Number(value);
|
|
30
|
-
index += 1;
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
if (option !== undefined)
|
|
34
|
-
rest.push(option);
|
|
35
|
-
}
|
|
36
|
-
return budget === undefined ? { ok: true, rest } : { ok: true, budget, rest };
|
|
37
|
-
};
|
|
38
|
-
const runProjection = (options, cwd, output) => {
|
|
39
|
-
const extracted = output === 'json' ? extractBudget(options) : { ok: true, rest: options };
|
|
40
|
-
if (!extracted.ok) {
|
|
41
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
42
|
-
}
|
|
43
|
-
const budget = 'budget' in extracted ? extracted.budget : undefined;
|
|
44
|
-
const [projectionPath, ...paths] = extracted.rest;
|
|
45
|
-
if (projectionPath === undefined ||
|
|
46
|
-
paths.length === 0 ||
|
|
47
|
-
extracted.rest.some((option) => option.startsWith('-'))) {
|
|
48
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
49
|
-
}
|
|
50
|
-
try {
|
|
51
|
-
const resolved = resolveCliWorkspaceSources(paths, cwd);
|
|
52
|
-
if (!resolved.ok) {
|
|
53
|
-
return {
|
|
54
|
-
exitCode: 1,
|
|
55
|
-
stdout: diagnosticJson(resolved.diagnostics),
|
|
56
|
-
stderr: '',
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
const loaded = loadProjection({
|
|
60
|
-
path: projectionPath,
|
|
61
|
-
source: readFileSync(resolve(cwd, projectionPath), 'utf8'),
|
|
62
|
-
});
|
|
63
|
-
if (!loaded.ok) {
|
|
64
|
-
return {
|
|
65
|
-
exitCode: 1,
|
|
66
|
-
stdout: diagnosticJson(loaded.diagnostics),
|
|
67
|
-
stderr: '',
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const compilation = compileWorkspaceWithProfileContext(resolved.paths.map((path) => ({
|
|
71
|
-
path,
|
|
72
|
-
source: readFileSync(resolve(cwd, path), 'utf8'),
|
|
73
|
-
})));
|
|
74
|
-
if (!compilation.ok) {
|
|
75
|
-
return {
|
|
76
|
-
exitCode: 1,
|
|
77
|
-
stdout: diagnosticJson(compilation.diagnostics),
|
|
78
|
-
stderr: '',
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
const result = evaluateProjection(compilation.graph, loaded.projection, compilation.profileContext);
|
|
82
|
-
return {
|
|
83
|
-
exitCode: 0,
|
|
84
|
-
stdout: output === 'json'
|
|
85
|
-
? budget === undefined
|
|
86
|
-
? `${JSON.stringify(result, null, 2)}\n`
|
|
87
|
-
: renderBudgetedContext(result, budget)
|
|
88
|
-
: renderProjectionMarkdown(result),
|
|
89
|
-
stderr: '',
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
94
|
-
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
const runAdHocContext = (options, cwd) => {
|
|
98
|
-
const extracted = extractBudget(options);
|
|
99
|
-
if (!extracted.ok) {
|
|
100
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
101
|
-
}
|
|
102
|
-
const budget = 'budget' in extracted ? extracted.budget : undefined;
|
|
103
|
-
const subjects = [];
|
|
104
|
-
const paths = [];
|
|
105
|
-
for (let index = 0; index < extracted.rest.length; index += 1) {
|
|
106
|
-
const option = extracted.rest[index];
|
|
107
|
-
if (option === '--subject') {
|
|
108
|
-
const value = extracted.rest[index + 1];
|
|
109
|
-
if (value === undefined || value.startsWith('-')) {
|
|
110
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
111
|
-
}
|
|
112
|
-
subjects.push(value);
|
|
113
|
-
index += 1;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
if (option === undefined || option.startsWith('-')) {
|
|
117
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
118
|
-
}
|
|
119
|
-
paths.push(option);
|
|
120
|
-
}
|
|
121
|
-
if (subjects.length === 0 || paths.length === 0) {
|
|
122
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
123
|
-
}
|
|
124
|
-
const unqualified = subjects.filter((subject) => !subject.includes('#'));
|
|
125
|
-
if (unqualified.length > 0) {
|
|
126
|
-
return {
|
|
127
|
-
exitCode: 2,
|
|
128
|
-
stdout: '',
|
|
129
|
-
stderr: 'Ad-hoc context subjects must be globally qualified as ' +
|
|
130
|
-
`"<document-id>#<local-id>": ${unqualified.join(', ')}\n`,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
try {
|
|
134
|
-
const resolved = resolveCliWorkspaceSources(paths, cwd);
|
|
135
|
-
if (!resolved.ok) {
|
|
136
|
-
return {
|
|
137
|
-
exitCode: 1,
|
|
138
|
-
stdout: diagnosticJson(resolved.diagnostics),
|
|
139
|
-
stderr: '',
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
const compilation = compileWorkspaceWithProfileContext(resolved.paths.map((path) => ({
|
|
143
|
-
path,
|
|
144
|
-
source: readFileSync(resolve(cwd, path), 'utf8'),
|
|
145
|
-
})));
|
|
146
|
-
if (!compilation.ok) {
|
|
147
|
-
return {
|
|
148
|
-
exitCode: 1,
|
|
149
|
-
stdout: diagnosticJson(compilation.diagnostics),
|
|
150
|
-
stderr: '',
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
const known = new Set(compilation.graph.subjects.map(({ id }) => id));
|
|
154
|
-
const unknown = subjects.filter((subject) => !known.has(subject));
|
|
155
|
-
if (unknown.length > 0) {
|
|
156
|
-
return {
|
|
157
|
-
exitCode: 1,
|
|
158
|
-
stdout: '',
|
|
159
|
-
stderr: `Unknown subject ${unknown.length === 1 ? 'identity' : 'identities'}: ` +
|
|
160
|
-
`${unknown.join(', ')} (the compiled workspace declares ${known.size} subjects)\n`,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
const result = evaluateProjection(compilation.graph, {
|
|
164
|
-
format: 'yarramate/projection/v1',
|
|
165
|
-
id: 'ad-hoc-context',
|
|
166
|
-
version: '0.0',
|
|
167
|
-
query: { subjects, relationships: 'connected' },
|
|
168
|
-
presentation: {
|
|
169
|
-
title: 'Ad-hoc context',
|
|
170
|
-
description: `Connected neighbourhood of ${subjects.join(', ')}`,
|
|
171
|
-
},
|
|
172
|
-
}, compilation.profileContext);
|
|
173
|
-
return {
|
|
174
|
-
exitCode: 0,
|
|
175
|
-
stdout: budget === undefined
|
|
176
|
-
? `${JSON.stringify(result, null, 2)}\n`
|
|
177
|
-
: renderBudgetedContext(result, budget),
|
|
178
|
-
stderr: '',
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
183
|
-
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
const runEvidence = (options, cwd) => {
|
|
187
|
-
const [evidencePath, ...paths] = options;
|
|
188
|
-
if (evidencePath === undefined ||
|
|
189
|
-
paths.length === 0 ||
|
|
190
|
-
options.some((option) => option.startsWith('-'))) {
|
|
191
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
192
|
-
}
|
|
193
|
-
try {
|
|
194
|
-
const resolved = resolveCliWorkspaceSources(paths, cwd);
|
|
195
|
-
if (!resolved.ok) {
|
|
196
|
-
return {
|
|
197
|
-
exitCode: 1,
|
|
198
|
-
stdout: diagnosticJson(resolved.diagnostics),
|
|
199
|
-
stderr: '',
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
const loaded = loadEvidence({
|
|
203
|
-
path: evidencePath,
|
|
204
|
-
source: readFileSync(resolve(cwd, evidencePath), 'utf8'),
|
|
205
|
-
});
|
|
206
|
-
if (!loaded.ok) {
|
|
207
|
-
return {
|
|
208
|
-
exitCode: 1,
|
|
209
|
-
stdout: diagnosticJson(loaded.diagnostics),
|
|
210
|
-
stderr: '',
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
const compilation = compileWorkspace(resolved.paths.map((path) => ({
|
|
214
|
-
path,
|
|
215
|
-
source: readFileSync(resolve(cwd, path), 'utf8'),
|
|
216
|
-
})));
|
|
217
|
-
if (!compilation.ok) {
|
|
218
|
-
return {
|
|
219
|
-
exitCode: 1,
|
|
220
|
-
stdout: diagnosticJson(compilation.diagnostics),
|
|
221
|
-
stderr: '',
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
const evaluation = evaluateEvidence(compilation.graph, loaded.evidence);
|
|
225
|
-
return evaluation.ok
|
|
226
|
-
? {
|
|
227
|
-
exitCode: 0,
|
|
228
|
-
stdout: `${JSON.stringify(evaluation.report, null, 2)}\n`,
|
|
229
|
-
stderr: '',
|
|
230
|
-
}
|
|
231
|
-
: {
|
|
232
|
-
exitCode: 1,
|
|
233
|
-
stdout: diagnosticJson(evaluation.diagnostics),
|
|
234
|
-
stderr: '',
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
239
|
-
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
14
|
const runReconciliation = (options, cwd) => {
|
|
243
15
|
const [workspacePath] = options;
|
|
244
16
|
if (options.length !== 1 ||
|
|
@@ -307,52 +79,6 @@ const runReconciliation = (options, cwd) => {
|
|
|
307
79
|
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
308
80
|
}
|
|
309
81
|
};
|
|
310
|
-
const runStateComparison = (options, cwd) => {
|
|
311
|
-
const [from, to, ...paths] = options;
|
|
312
|
-
if (from === undefined ||
|
|
313
|
-
to === undefined ||
|
|
314
|
-
paths.length === 0 ||
|
|
315
|
-
options.some((option) => option.startsWith('-'))) {
|
|
316
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
317
|
-
}
|
|
318
|
-
try {
|
|
319
|
-
const resolved = resolveCliWorkspaceSources(paths, cwd);
|
|
320
|
-
if (!resolved.ok) {
|
|
321
|
-
return {
|
|
322
|
-
exitCode: 1,
|
|
323
|
-
stdout: diagnosticJson(resolved.diagnostics),
|
|
324
|
-
stderr: '',
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
const compilation = compileWorkspace(resolved.paths.map((path) => ({
|
|
328
|
-
path,
|
|
329
|
-
source: readFileSync(resolve(cwd, path), 'utf8'),
|
|
330
|
-
})));
|
|
331
|
-
if (!compilation.ok) {
|
|
332
|
-
return {
|
|
333
|
-
exitCode: 1,
|
|
334
|
-
stdout: diagnosticJson(compilation.diagnostics),
|
|
335
|
-
stderr: '',
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
const comparison = compareArchitectureStates(compilation.graph, from, to);
|
|
339
|
-
return comparison.ok
|
|
340
|
-
? {
|
|
341
|
-
exitCode: 0,
|
|
342
|
-
stdout: `${JSON.stringify(comparison.comparison, null, 2)}\n`,
|
|
343
|
-
stderr: '',
|
|
344
|
-
}
|
|
345
|
-
: {
|
|
346
|
-
exitCode: 2,
|
|
347
|
-
stdout: '',
|
|
348
|
-
stderr: `${comparison.issues.map(({ message }) => message).join('\n')}\n`,
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
catch (error) {
|
|
352
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
353
|
-
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
82
|
const runInit = (options, cwd) => {
|
|
357
83
|
const positional = options.filter((option) => option !== '--no-pointer');
|
|
358
84
|
const writePointer = positional.length === options.length;
|
|
@@ -399,9 +125,9 @@ const runInit = (options, cwd) => {
|
|
|
399
125
|
'YarraMate documents in `.yarramate/`. When prose documentation and the\n' +
|
|
400
126
|
'model disagree, the model is authoritative.\n' +
|
|
401
127
|
'\n' +
|
|
402
|
-
'- Orient first: `yarramate
|
|
128
|
+
'- Orient first: `yarramate ask .yarramate/workspace.yaml`\n' +
|
|
129
|
+
'- Continue the design interview: `yarramate design .yarramate/workspace.yaml`\n' +
|
|
403
130
|
'- Validate changes: `yarramate check .yarramate/workspace.yaml --json`\n' +
|
|
404
|
-
'- Bounded task context: `yarramate context <projection.yaml> .yarramate/workspace.yaml`\n' +
|
|
405
131
|
'\n' +
|
|
406
132
|
'Author native documents only; never edit generated output.\n';
|
|
407
133
|
// Harnesses look in different files: AGENTS.md is the cross-harness
|
|
@@ -435,283 +161,9 @@ const runInit = (options, cwd) => {
|
|
|
435
161
|
stderr: '',
|
|
436
162
|
};
|
|
437
163
|
};
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
return undefined;
|
|
442
|
-
}
|
|
443
|
-
const flags = new Map();
|
|
444
|
-
for (let index = 0; index < rest.length; index += 2) {
|
|
445
|
-
const flag = rest[index];
|
|
446
|
-
const value = rest[index + 1];
|
|
447
|
-
if (flag === undefined ||
|
|
448
|
-
value === undefined ||
|
|
449
|
-
!flag.startsWith('--') ||
|
|
450
|
-
value.startsWith('--')) {
|
|
451
|
-
return undefined;
|
|
452
|
-
}
|
|
453
|
-
flags.set(flag, [...(flags.get(flag) ?? []), value]);
|
|
454
|
-
}
|
|
455
|
-
return { path, flags };
|
|
456
|
-
};
|
|
457
|
-
const oneFlag = (flags, flag) => {
|
|
458
|
-
const values = flags.get(flag);
|
|
459
|
-
return values?.length === 1 ? values[0] : undefined;
|
|
460
|
-
};
|
|
461
|
-
const hasRepeatedSingletonFlag = (flags) => [...flags.entries()].some(([flag, values]) => flag !== '--source' &&
|
|
462
|
-
flag !== '--constraint' &&
|
|
463
|
-
flag !== '--reference' &&
|
|
464
|
-
flag !== '--present-in' &&
|
|
465
|
-
values.length !== 1);
|
|
466
|
-
const appendBlockItem = (document, collection, item) => {
|
|
467
|
-
document.addIn([collection], item);
|
|
468
|
-
const sequence = document.getIn([collection], true);
|
|
469
|
-
if (isSeq(sequence)) {
|
|
470
|
-
sequence.flow = false;
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
const identifiedReferences = (values) => {
|
|
474
|
-
const parsed = values.map((value) => {
|
|
475
|
-
const separator = value.indexOf('=');
|
|
476
|
-
return separator <= 0 || separator === value.length - 1
|
|
477
|
-
? undefined
|
|
478
|
-
: {
|
|
479
|
-
id: value.slice(0, separator),
|
|
480
|
-
ref: value.slice(separator + 1),
|
|
481
|
-
};
|
|
482
|
-
});
|
|
483
|
-
return parsed.some((reference) => reference === undefined)
|
|
484
|
-
? undefined
|
|
485
|
-
: parsed;
|
|
486
|
-
};
|
|
487
|
-
const runAdd = (options, cwd) => {
|
|
488
|
-
const parsed = parseFlags(options);
|
|
489
|
-
if (parsed === undefined) {
|
|
490
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
491
|
-
}
|
|
492
|
-
const allowed = new Set([
|
|
493
|
-
'--id',
|
|
494
|
-
'--kind',
|
|
495
|
-
'--name',
|
|
496
|
-
'--status',
|
|
497
|
-
'--description',
|
|
498
|
-
'--owner',
|
|
499
|
-
'--constraint',
|
|
500
|
-
'--reference',
|
|
501
|
-
'--present-in',
|
|
502
|
-
'--source',
|
|
503
|
-
]);
|
|
504
|
-
if ([...parsed.flags.keys()].some((flag) => !allowed.has(flag)) ||
|
|
505
|
-
hasRepeatedSingletonFlag(parsed.flags)) {
|
|
506
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
507
|
-
}
|
|
508
|
-
const id = oneFlag(parsed.flags, '--id');
|
|
509
|
-
const kind = oneFlag(parsed.flags, '--kind');
|
|
510
|
-
const name = oneFlag(parsed.flags, '--name');
|
|
511
|
-
if (id === undefined || kind === undefined || name === undefined) {
|
|
512
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
513
|
-
}
|
|
514
|
-
const constraints = identifiedReferences(parsed.flags.get('--constraint') ?? []);
|
|
515
|
-
const references = identifiedReferences(parsed.flags.get('--reference') ?? []);
|
|
516
|
-
if (constraints === undefined || references === undefined) {
|
|
517
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
518
|
-
}
|
|
519
|
-
try {
|
|
520
|
-
const absolutePath = resolve(cwd, parsed.path);
|
|
521
|
-
const document = parseDocument(readFileSync(absolutePath, 'utf8'));
|
|
522
|
-
appendBlockItem(document, 'concepts', {
|
|
523
|
-
id,
|
|
524
|
-
kind,
|
|
525
|
-
name,
|
|
526
|
-
...(oneFlag(parsed.flags, '--description') === undefined
|
|
527
|
-
? {}
|
|
528
|
-
: { description: oneFlag(parsed.flags, '--description') }),
|
|
529
|
-
...(oneFlag(parsed.flags, '--status') === undefined
|
|
530
|
-
? {}
|
|
531
|
-
: { status: oneFlag(parsed.flags, '--status') }),
|
|
532
|
-
...(oneFlag(parsed.flags, '--owner') === undefined
|
|
533
|
-
? {}
|
|
534
|
-
: { owner: oneFlag(parsed.flags, '--owner') }),
|
|
535
|
-
...(constraints.length === 0 ? {} : { constraints }),
|
|
536
|
-
...(references.length === 0 ? {} : { references }),
|
|
537
|
-
...(parsed.flags.get('--present-in') === undefined
|
|
538
|
-
? {}
|
|
539
|
-
: { presentIn: parsed.flags.get('--present-in') }),
|
|
540
|
-
});
|
|
541
|
-
const candidate = document.toString({ lineWidth: 0 });
|
|
542
|
-
const companions = resolveCliWorkspaceSources(parsed.flags.get('--source') ?? [], cwd);
|
|
543
|
-
if (!companions.ok) {
|
|
544
|
-
return {
|
|
545
|
-
exitCode: 1,
|
|
546
|
-
stdout: humanDiagnostics(companions.diagnostics),
|
|
547
|
-
stderr: '',
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
const compilation = compileWorkspace([
|
|
551
|
-
{ path: parsed.path, source: candidate },
|
|
552
|
-
...companions.paths
|
|
553
|
-
.filter((path) => resolve(cwd, path) !== resolve(cwd, parsed.path))
|
|
554
|
-
.map((path) => ({
|
|
555
|
-
path,
|
|
556
|
-
source: readFileSync(resolve(cwd, path), 'utf8'),
|
|
557
|
-
})),
|
|
558
|
-
]);
|
|
559
|
-
if (!compilation.ok) {
|
|
560
|
-
return {
|
|
561
|
-
exitCode: 1,
|
|
562
|
-
stdout: humanDiagnostics(compilation.diagnostics),
|
|
563
|
-
stderr: '',
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
writeFileSync(absolutePath, candidate, 'utf8');
|
|
567
|
-
return {
|
|
568
|
-
exitCode: 0,
|
|
569
|
-
stdout: `Added concept "${id}" to ${parsed.path}\n`,
|
|
570
|
-
stderr: '',
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
catch (error) {
|
|
574
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
575
|
-
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
const runConnect = (options, cwd) => {
|
|
579
|
-
const parsed = parseFlags(options);
|
|
580
|
-
if (parsed === undefined) {
|
|
581
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
582
|
-
}
|
|
583
|
-
const allowed = new Set([
|
|
584
|
-
'--id',
|
|
585
|
-
'--kind',
|
|
586
|
-
'--from',
|
|
587
|
-
'--to',
|
|
588
|
-
'--name',
|
|
589
|
-
'--description',
|
|
590
|
-
'--status',
|
|
591
|
-
'--mode',
|
|
592
|
-
'--content',
|
|
593
|
-
'--reference',
|
|
594
|
-
'--present-in',
|
|
595
|
-
'--source',
|
|
596
|
-
]);
|
|
597
|
-
if ([...parsed.flags.keys()].some((flag) => !allowed.has(flag)) ||
|
|
598
|
-
hasRepeatedSingletonFlag(parsed.flags)) {
|
|
599
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
600
|
-
}
|
|
601
|
-
const id = oneFlag(parsed.flags, '--id');
|
|
602
|
-
const kind = oneFlag(parsed.flags, '--kind');
|
|
603
|
-
const from = oneFlag(parsed.flags, '--from');
|
|
604
|
-
const to = oneFlag(parsed.flags, '--to');
|
|
605
|
-
if (id === undefined ||
|
|
606
|
-
kind === undefined ||
|
|
607
|
-
from === undefined ||
|
|
608
|
-
to === undefined) {
|
|
609
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
610
|
-
}
|
|
611
|
-
const references = identifiedReferences(parsed.flags.get('--reference') ?? []);
|
|
612
|
-
if (references === undefined) {
|
|
613
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
614
|
-
}
|
|
615
|
-
try {
|
|
616
|
-
const absolutePath = resolve(cwd, parsed.path);
|
|
617
|
-
const document = parseDocument(readFileSync(absolutePath, 'utf8'));
|
|
618
|
-
appendBlockItem(document, 'relationships', {
|
|
619
|
-
id,
|
|
620
|
-
kind,
|
|
621
|
-
from,
|
|
622
|
-
to,
|
|
623
|
-
...(oneFlag(parsed.flags, '--name') === undefined
|
|
624
|
-
? {}
|
|
625
|
-
: { name: oneFlag(parsed.flags, '--name') }),
|
|
626
|
-
...(oneFlag(parsed.flags, '--description') === undefined
|
|
627
|
-
? {}
|
|
628
|
-
: { description: oneFlag(parsed.flags, '--description') }),
|
|
629
|
-
...(oneFlag(parsed.flags, '--status') === undefined
|
|
630
|
-
? {}
|
|
631
|
-
: { status: oneFlag(parsed.flags, '--status') }),
|
|
632
|
-
...(oneFlag(parsed.flags, '--mode') === undefined
|
|
633
|
-
? {}
|
|
634
|
-
: { mode: oneFlag(parsed.flags, '--mode') }),
|
|
635
|
-
...(oneFlag(parsed.flags, '--content') === undefined
|
|
636
|
-
? {}
|
|
637
|
-
: { content: oneFlag(parsed.flags, '--content') }),
|
|
638
|
-
...(references.length === 0 ? {} : { references }),
|
|
639
|
-
...(parsed.flags.get('--present-in') === undefined
|
|
640
|
-
? {}
|
|
641
|
-
: { presentIn: parsed.flags.get('--present-in') }),
|
|
642
|
-
});
|
|
643
|
-
const candidate = document.toString({ lineWidth: 0 });
|
|
644
|
-
const companions = resolveCliWorkspaceSources(parsed.flags.get('--source') ?? [], cwd);
|
|
645
|
-
if (!companions.ok) {
|
|
646
|
-
return {
|
|
647
|
-
exitCode: 1,
|
|
648
|
-
stdout: humanDiagnostics(companions.diagnostics),
|
|
649
|
-
stderr: '',
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
|
-
const compilation = compileWorkspace([
|
|
653
|
-
{ path: parsed.path, source: candidate },
|
|
654
|
-
...companions.paths
|
|
655
|
-
.filter((path) => resolve(cwd, path) !== resolve(cwd, parsed.path))
|
|
656
|
-
.map((path) => ({
|
|
657
|
-
path,
|
|
658
|
-
source: readFileSync(resolve(cwd, path), 'utf8'),
|
|
659
|
-
})),
|
|
660
|
-
]);
|
|
661
|
-
if (!compilation.ok) {
|
|
662
|
-
return {
|
|
663
|
-
exitCode: 1,
|
|
664
|
-
stdout: humanDiagnostics(compilation.diagnostics),
|
|
665
|
-
stderr: '',
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
writeFileSync(absolutePath, candidate, 'utf8');
|
|
669
|
-
return {
|
|
670
|
-
exitCode: 0,
|
|
671
|
-
stdout: `Added relationship "${id}" to ${parsed.path}\n`,
|
|
672
|
-
stderr: '',
|
|
673
|
-
};
|
|
674
|
-
}
|
|
675
|
-
catch (error) {
|
|
676
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
677
|
-
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
const runCompile = (options, cwd) => {
|
|
681
|
-
if (options.length === 0 ||
|
|
682
|
-
options.some((option) => option.startsWith('-'))) {
|
|
683
|
-
return { exitCode: 2, stdout: '', stderr: usage };
|
|
684
|
-
}
|
|
685
|
-
try {
|
|
686
|
-
const resolved = resolveCliWorkspaceSources(options, cwd);
|
|
687
|
-
if (!resolved.ok) {
|
|
688
|
-
return {
|
|
689
|
-
exitCode: 1,
|
|
690
|
-
stdout: humanDiagnostics(resolved.diagnostics),
|
|
691
|
-
stderr: '',
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
const result = compileWorkspace(resolved.paths.map((path) => ({
|
|
695
|
-
path,
|
|
696
|
-
source: readFileSync(resolve(cwd, path), 'utf8'),
|
|
697
|
-
})));
|
|
698
|
-
return result.ok
|
|
699
|
-
? {
|
|
700
|
-
exitCode: 0,
|
|
701
|
-
stdout: serializeSemanticGraph(result.graph),
|
|
702
|
-
stderr: '',
|
|
703
|
-
}
|
|
704
|
-
: {
|
|
705
|
-
exitCode: 1,
|
|
706
|
-
stdout: humanDiagnostics(result.diagnostics),
|
|
707
|
-
stderr: '',
|
|
708
|
-
};
|
|
709
|
-
}
|
|
710
|
-
catch (error) {
|
|
711
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
712
|
-
return { exitCode: 2, stdout: '', stderr: `${message}\n` };
|
|
713
|
-
}
|
|
714
|
-
};
|
|
164
|
+
// The seven-verb contract (docs/AGENT-INTERFACE.md): one verb per
|
|
165
|
+
// lifecycle stage — init creates, design fills, apply writes, ask reads,
|
|
166
|
+
// check gates, reconcile reports drift, export derives artifacts.
|
|
715
167
|
export function runCli(args, cwd = process.cwd()) {
|
|
716
168
|
const [command, ...options] = args;
|
|
717
169
|
if (command === '--help' || command === '-h' || command === 'help') {
|
|
@@ -723,43 +175,23 @@ export function runCli(args, cwd = process.cwd()) {
|
|
|
723
175
|
if (command === 'init') {
|
|
724
176
|
return runInit(options, cwd);
|
|
725
177
|
}
|
|
726
|
-
if (command === '
|
|
727
|
-
return
|
|
728
|
-
}
|
|
729
|
-
if (command === 'connect') {
|
|
730
|
-
return runConnect(options, cwd);
|
|
731
|
-
}
|
|
732
|
-
if (command === 'compile') {
|
|
733
|
-
return runCompile(options, cwd);
|
|
734
|
-
}
|
|
735
|
-
if (command === 'context') {
|
|
736
|
-
return options.includes('--subject')
|
|
737
|
-
? runAdHocContext(options, cwd)
|
|
738
|
-
: runProjection(options, cwd, 'json');
|
|
178
|
+
if (command === 'design') {
|
|
179
|
+
return runDesignCommand(options, cwd);
|
|
739
180
|
}
|
|
740
|
-
if (command === '
|
|
741
|
-
return
|
|
181
|
+
if (command === 'apply') {
|
|
182
|
+
return runApplyCommand(options, cwd);
|
|
742
183
|
}
|
|
743
|
-
if (command === '
|
|
744
|
-
return
|
|
745
|
-
}
|
|
746
|
-
if (command === 'evidence') {
|
|
747
|
-
return runEvidence(options, cwd);
|
|
748
|
-
}
|
|
749
|
-
if (command === 'reconcile') {
|
|
750
|
-
return runReconciliation(options, cwd);
|
|
184
|
+
if (command === 'ask') {
|
|
185
|
+
return runAskCommand(options, cwd);
|
|
751
186
|
}
|
|
752
187
|
if (command === 'check') {
|
|
753
188
|
return runCheckCommand(options, cwd);
|
|
754
189
|
}
|
|
755
|
-
if (command === '
|
|
756
|
-
return
|
|
757
|
-
}
|
|
758
|
-
if (command === 'new') {
|
|
759
|
-
return runNewCommand(options, cwd);
|
|
190
|
+
if (command === 'reconcile') {
|
|
191
|
+
return runReconciliation(options, cwd);
|
|
760
192
|
}
|
|
761
|
-
if (command === '
|
|
762
|
-
return
|
|
193
|
+
if (command === 'export') {
|
|
194
|
+
return runExportCommand(options, cwd);
|
|
763
195
|
}
|
|
764
196
|
return { exitCode: 2, stdout: '', stderr: usage };
|
|
765
197
|
}
|
package/dist/compiler.js
CHANGED
|
@@ -911,6 +911,19 @@ function compileWorkspaceResolved(sources) {
|
|
|
911
911
|
source: location(['concepts', index, 'references', referenceIndex, 'ref'], `/concepts/${index}/references/${referenceIndex}/ref`),
|
|
912
912
|
});
|
|
913
913
|
}
|
|
914
|
+
// An attestation is a recorded judgment, not content the engine
|
|
915
|
+
// evaluates: the claim's existence is what triggers can see, and
|
|
916
|
+
// revocation is deletion, reviewed at the Git boundary.
|
|
917
|
+
for (const [attestationIndex, attestation] of (concept.attestations ?? []).entries()) {
|
|
918
|
+
claims.push({
|
|
919
|
+
id: `${subject}~attestation-${attestation.topic}`,
|
|
920
|
+
subject,
|
|
921
|
+
predicate: `yarramate/attestation/${attestation.topic}`,
|
|
922
|
+
object: { value: `${attestation.by} ${attestation.on}` },
|
|
923
|
+
origin: 'declared',
|
|
924
|
+
source: location(['concepts', index, 'attestations', attestationIndex, 'topic'], `/concepts/${index}/attestations/${attestationIndex}/topic`),
|
|
925
|
+
});
|
|
926
|
+
}
|
|
914
927
|
for (const [stateIndex, state] of (concept.presentIn ?? []).entries()) {
|
|
915
928
|
const stateIdentity = qualifyReference(value.id, state);
|
|
916
929
|
claims.push({
|
package/dist/core-contract.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface CoreContractFormat {
|
|
|
5
5
|
readonly packageExport: string;
|
|
6
6
|
}
|
|
7
7
|
export interface CoreContractCommand {
|
|
8
|
-
readonly name: 'init' | '
|
|
8
|
+
readonly name: 'init' | 'design' | 'apply' | 'ask' | 'check' | 'reconcile' | 'export';
|
|
9
9
|
readonly binary: 'yarramate';
|
|
10
10
|
readonly machineFormat?: string;
|
|
11
11
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type CliResult } from './cli-support.js';
|
|
2
|
-
export declare function
|
|
2
|
+
export declare function runDesignCommand(options: readonly string[], cwd: string): CliResult;
|