yarramate 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +39 -12
  2. package/catalogues/core-enrichment.yaml +700 -0
  3. package/dist/adapters/mcp-cli.js +55 -49
  4. package/dist/apply-command.d.ts +2 -0
  5. package/dist/apply-command.js +346 -0
  6. package/dist/{new-command.d.ts → ask-command.d.ts} +1 -1
  7. package/dist/ask-command.js +729 -0
  8. package/dist/brief.d.ts +3 -0
  9. package/dist/brief.js +235 -0
  10. package/dist/cli-support.d.ts +1 -1
  11. package/dist/cli-support.js +1 -1
  12. package/dist/cli.js +22 -590
  13. package/dist/compiler.js +13 -0
  14. package/dist/core-contract.d.ts +1 -1
  15. package/dist/{status-command.d.ts → design-command.d.ts} +1 -1
  16. package/dist/design-command.js +222 -0
  17. package/dist/export-command.d.ts +2 -0
  18. package/dist/export-command.js +228 -0
  19. package/dist/interrogate-command.d.ts +104 -0
  20. package/dist/interrogate-command.js +268 -0
  21. package/dist/next-command.d.ts +5 -8
  22. package/dist/next-command.js +106 -211
  23. package/docs/CONSUMING-YARRAMATE.md +28 -21
  24. package/package.json +13 -11
  25. package/schema/yarramate-apply-result.schema.json +32 -0
  26. package/schema/yarramate-ask-result.schema.json +391 -0
  27. package/schema/yarramate-core-contract.schema.json +5 -11
  28. package/schema/yarramate-design-step.schema.json +160 -0
  29. package/schema/yarramate-document.schema.json +76 -9
  30. package/schema/yarramate-interrogation-report.schema.json +89 -0
  31. package/schema/yarramate-operations.schema.json +334 -0
  32. package/schema/yarramate-question-catalogue.schema.json +431 -0
  33. package/skills/yarramate-architecture/SKILL.md +46 -17
  34. package/skills/yarramate-architecture/references/native-authoring.md +73 -17
  35. package/dist/new-command.js +0 -111
  36. package/dist/status-command.js +0 -174
  37. package/schema/yarramate-next-result.schema.json +0 -85
  38. package/schema/yarramate-status-result.schema.json +0 -278
@@ -10,14 +10,65 @@ const workspaceProperty = {
10
10
  };
11
11
  const tools = [
12
12
  {
13
- name: 'yarramate_status',
14
- description: 'One-call workspace orientation: check verdict, reconciliation summary, and a titled inventory of documents, states, projections, evidence, and contracts.',
13
+ name: 'yarramate_ask',
14
+ description: 'The consumed-now read surface. Without a query: orientation — check verdict, drift summary, open-question count, and the backlog in dependency order. With a query: free text matches concept ids, names, and descriptions and returns the connected slice; exact subject ids (document-id#local-id) and projection paths address precisely. Set mode for the roster (subjects), declarable vocabulary (kinds), build order (next), or the full open-questions report (open).',
15
15
  inputSchema: {
16
16
  type: 'object',
17
17
  required: ['workspace'],
18
- properties: workspaceProperty,
18
+ properties: {
19
+ ...workspaceProperty,
20
+ query: {
21
+ type: 'string',
22
+ description: 'Free text, a globally qualified subject id, or a projection path',
23
+ },
24
+ mode: {
25
+ type: 'string',
26
+ enum: ['subjects', 'kinds', 'next', 'open'],
27
+ description: 'Optional flag mode instead of a query: the filterable roster, the declarable kind vocabulary, dependency-ordered planned work, or the open-questions report',
28
+ },
29
+ budget: {
30
+ type: 'integer',
31
+ minimum: 1,
32
+ description: 'Approximate token budget for the compact slice rendering (query form only)',
33
+ },
34
+ },
35
+ },
36
+ arguments: (input) => {
37
+ const workspace = String(input.workspace);
38
+ if (typeof input.mode === 'string') {
39
+ return ['ask', workspace, `--${input.mode}`, '--json'];
40
+ }
41
+ if (typeof input.query === 'string' && input.query.length > 0) {
42
+ const budget = typeof input.budget === 'number'
43
+ ? ['--budget', String(input.budget)]
44
+ : ['--json'];
45
+ return ['ask', workspace, input.query, ...budget];
46
+ }
47
+ return ['ask', workspace, '--json'];
48
+ },
49
+ },
50
+ {
51
+ name: 'yarramate_design',
52
+ description: 'The design interview, one stateless step: the top open question with its subject slice, materiality, and progress. Read-only — answers land through the CLI apply command in the repository, not through this server.',
53
+ inputSchema: {
54
+ type: 'object',
55
+ required: ['workspace'],
56
+ properties: {
57
+ ...workspaceProperty,
58
+ subject: {
59
+ type: 'string',
60
+ description: 'Optional globally qualified subject id to narrow the interview',
61
+ },
62
+ },
19
63
  },
20
- arguments: (input) => ['status', String(input.workspace), '--json'],
64
+ arguments: (input) => [
65
+ 'design',
66
+ String(input.workspace),
67
+ ...(typeof input.subject === 'string'
68
+ ? ['--subject', input.subject]
69
+ : []),
70
+ '--json',
71
+ ],
21
72
  },
22
73
  {
23
74
  name: 'yarramate_check',
@@ -39,51 +90,6 @@ const tools = [
39
90
  },
40
91
  arguments: (input) => ['reconcile', String(input.workspace)],
41
92
  },
42
- {
43
- name: 'yarramate_context',
44
- description: 'Bounded architecture context. Provide either a projection path or one or more globally qualified subjects (document-id#local-id) for an ad-hoc connected neighbourhood. Optional token budget switches to a compact ranked rendering.',
45
- inputSchema: {
46
- type: 'object',
47
- required: ['workspace'],
48
- properties: {
49
- ...workspaceProperty,
50
- projection: {
51
- type: 'string',
52
- description: 'Path to an authored projection definition',
53
- },
54
- subjects: {
55
- type: 'array',
56
- items: { type: 'string' },
57
- description: 'Globally qualified subject identities for ad-hoc context',
58
- },
59
- budget: {
60
- type: 'integer',
61
- minimum: 1,
62
- description: 'Approximate token budget for the compact rendering',
63
- },
64
- },
65
- },
66
- arguments: (input) => {
67
- const budget = typeof input.budget === 'number'
68
- ? ['--budget', String(input.budget)]
69
- : [];
70
- if (typeof input.projection === 'string') {
71
- return [
72
- 'context',
73
- input.projection,
74
- String(input.workspace),
75
- ...budget,
76
- ];
77
- }
78
- const subjects = Array.isArray(input.subjects)
79
- ? input.subjects.flatMap((subject) => [
80
- '--subject',
81
- String(subject),
82
- ])
83
- : [];
84
- return ['context', ...subjects, String(input.workspace), ...budget];
85
- },
86
- },
87
93
  ];
88
94
  const respond = (id, result) => {
89
95
  process.stdout.write(`${JSON.stringify({ jsonrpc: '2.0', id, result })}\n`);
@@ -0,0 +1,2 @@
1
+ import { type CliResult } from './cli-support.js';
2
+ export declare function runApplyCommand(options: readonly string[], cwd: string): CliResult;
@@ -0,0 +1,346 @@
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { isMap, isScalar, isSeq, parseDocument, stringify, } from 'yaml';
4
+ import Ajv2020Module from 'ajv/dist/2020.js';
5
+ import { diagnosticJson, humanDiagnostics, usage, } from './cli-support.js';
6
+ import { compileWorkspace } from './compiler.js';
7
+ import { loadSourceDocument, locateSourcePath, } from './source-document.js';
8
+ import { loadWorkspaceManifest } from './workspace.js';
9
+ import operationsSchema from '../schema/yarramate-operations.schema.json' with {
10
+ type: 'json'
11
+ };
12
+ const Ajv2020 = Ajv2020Module.default;
13
+ const validateOperations = new Ajv2020({ allErrors: true }).compile(operationsSchema);
14
+ // Scalar fields replace; list fields append; `remove` retracts (ADR 0062).
15
+ // An answer enriches what is there and may explicitly take back what it
16
+ // asserted — it never silently shrinks anything.
17
+ const SCALAR_CONCEPT_FIELDS = ['kind', 'name', 'description', 'status', 'owner'];
18
+ const LIST_CONCEPT_FIELDS = ['constraints', 'references', 'presentIn', 'attestations'];
19
+ const SCALAR_RELATIONSHIP_FIELDS = ['kind', 'from', 'to', 'name', 'description', 'status', 'mode', 'content'];
20
+ const LIST_RELATIONSHIP_FIELDS = ['references', 'presentIn'];
21
+ // ---------------------------------------------------------------------------
22
+ // The splice layer. Every operation becomes a minimal text edit against the
23
+ // document's current source, so bytes the batch never touched stay
24
+ // byte-identical — an apply diff is exactly the answer it landed (#114).
25
+ // The atomic compile gate below validates the spliced text itself, so any
26
+ // splice defect rejects the batch loudly instead of corrupting a document.
27
+ const lineStartOf = (source, offset) => source.lastIndexOf('\n', offset - 1) + 1;
28
+ const indentAt = (source, offset) => offset - lineStartOf(source, offset);
29
+ // End of the last line a node occupies, extended through its newline.
30
+ const lineEndAfter = (source, offset) => {
31
+ const newline = source.indexOf('\n', Math.max(offset - 1, 0));
32
+ return newline === -1 ? source.length : newline + 1;
33
+ };
34
+ const reindent = (text, indent) => text.split('\n').join(`\n${' '.repeat(indent)}`);
35
+ // A plain value as YAML source. lineWidth 0 keeps strings we author on one
36
+ // line; genuinely multi-line strings become block scalars and are re-indented
37
+ // by the caller.
38
+ const valueText = (value) => stringify(value, { lineWidth: 0 }).trimEnd();
39
+ const pairFor = (map, key) => map.items.find((pair) => isScalar(pair.key) && pair.key.value === key);
40
+ const nodeRange = (node) => {
41
+ const range = node.range;
42
+ if (range === undefined) {
43
+ throw new Error('YAML node has no source range');
44
+ }
45
+ return range;
46
+ };
47
+ // Renders `items` as block sequence entries at the given marker indent.
48
+ const sequenceEntries = (items, markerIndent) => {
49
+ const rendered = stringify(items, { lineWidth: 0 }).trimEnd();
50
+ return `${' '.repeat(markerIndent)}${reindent(rendered, markerIndent)}`;
51
+ };
52
+ const splice = (source, start, end, text) => source.slice(0, start) + text + source.slice(end);
53
+ // Insert a newline-terminated block at a line boundary, tolerating a
54
+ // source that does not end in a newline.
55
+ const insertBlock = (source, insertAt, block) => splice(source, insertAt, insertAt, insertAt > 0 && source[insertAt - 1] !== '\n' ? `\n${block}` : block);
56
+ // Node ranges may extend past their trailing newline to the start of the
57
+ // next line; anchor insertions on the last CONTENT line instead.
58
+ const afterContentLine = (source, offset) => {
59
+ let anchor = offset;
60
+ while (anchor > 0 && source[anchor - 1] === '\n')
61
+ anchor -= 1;
62
+ return lineEndAfter(source, anchor);
63
+ };
64
+ // Where a new field of an item lands: after the last line of the item's
65
+ // final pair.
66
+ const itemFieldInsertAt = (source, map) => {
67
+ const lastPair = map.items[map.items.length - 1];
68
+ const anchor = lastPair.value === null || lastPair.value === undefined
69
+ ? nodeRange(lastPair.key)[2]
70
+ : nodeRange(lastPair.value)[1];
71
+ return afterContentLine(source, anchor);
72
+ };
73
+ // Appends one item to a top-level block collection (`concepts:` or
74
+ // `relationships:`), creating or converting the collection when needed.
75
+ const appendCollectionItem = (source, collection, item) => {
76
+ const document = parseDocument(source);
77
+ const root = document.contents;
78
+ if (!isMap(root))
79
+ throw new Error('Document root is not a mapping');
80
+ const pair = pairFor(root, collection);
81
+ if (pair === undefined) {
82
+ const base = source.endsWith('\n') ? source : `${source}\n`;
83
+ return `${base}${collection}:\n${sequenceEntries([item], 2)}\n`;
84
+ }
85
+ const sequence = pair.value;
86
+ if (isSeq(sequence) && !sequence.flow && sequence.items.length > 0) {
87
+ const lastItem = sequence.items[sequence.items.length - 1];
88
+ const markerIndent = indentAt(source, nodeRange(lastItem)[0]) - 2;
89
+ const insertAt = lineEndAfter(source, nodeRange(lastItem)[2]);
90
+ return insertBlock(source, insertAt, `${sequenceEntries([item], markerIndent)}\n`);
91
+ }
92
+ if (!isSeq(sequence)) {
93
+ // `concepts:` with no value at all: append the block under the key.
94
+ const insertAt = lineEndAfter(source, nodeRange(pair.key)[2]);
95
+ return insertBlock(source, insertAt, `${sequenceEntries([item], 2)}\n`);
96
+ }
97
+ // Empty or flow collection: replace the whole value with a block
98
+ // sequence carrying any existing entries plus the new one, consuming
99
+ // the space that separated it from the key.
100
+ const existing = sequence.items.length > 0
101
+ ? sequence.toJSON()
102
+ : [];
103
+ let [start] = nodeRange(sequence);
104
+ const valueEnd = nodeRange(sequence)[1];
105
+ while (start > 0 && source[start - 1] === ' ')
106
+ start -= 1;
107
+ return splice(source, start, valueEnd, `\n${sequenceEntries([...existing, item], 2)}`);
108
+ };
109
+ const itemMap = (source, collection, id) => {
110
+ const document = parseDocument(source);
111
+ const root = document.contents;
112
+ if (!isMap(root))
113
+ return undefined;
114
+ const pair = pairFor(root, collection);
115
+ if (pair === undefined || !isSeq(pair.value))
116
+ return undefined;
117
+ const found = pair.value.items.find((candidate) => isMap(candidate) &&
118
+ candidate.items.some((field) => isScalar(field.key) &&
119
+ field.key.value === 'id' &&
120
+ isScalar(field.value) &&
121
+ field.value.value === id));
122
+ return found === undefined ? undefined : { map: found };
123
+ };
124
+ // The indent item fields sit at, read off the item's own first field.
125
+ const fieldIndentOf = (source, map) => indentAt(source, nodeRange(map.items[0].key)[0]);
126
+ const setScalarField = (source, map, key, value) => {
127
+ const indent = fieldIndentOf(source, map);
128
+ const rendered = reindent(valueText(value), indent + 2);
129
+ const pair = pairFor(map, key);
130
+ if (pair === undefined) {
131
+ return insertBlock(source, itemFieldInsertAt(source, map), `${' '.repeat(indent)}${key}: ${rendered}\n`);
132
+ }
133
+ const [start, valueEnd] = nodeRange(pair.value);
134
+ return splice(source, start, valueEnd, rendered);
135
+ };
136
+ const appendListField = (source, map, key, additions) => {
137
+ const indent = fieldIndentOf(source, map);
138
+ const pair = pairFor(map, key);
139
+ if (pair === undefined) {
140
+ return insertBlock(source, itemFieldInsertAt(source, map), `${' '.repeat(indent)}${key}:\n${sequenceEntries(additions, indent + 2)}\n`);
141
+ }
142
+ const sequence = pair.value;
143
+ if (isSeq(sequence) && !sequence.flow && sequence.items.length > 0) {
144
+ const lastItem = sequence.items[sequence.items.length - 1];
145
+ const markerIndent = indentAt(source, nodeRange(lastItem)[0]) - 2;
146
+ const insertAt = lineEndAfter(source, nodeRange(lastItem)[2]);
147
+ return insertBlock(source, insertAt, `${sequenceEntries(additions, markerIndent)}\n`);
148
+ }
149
+ const existing = isSeq(sequence) && sequence.items.length > 0
150
+ ? sequence.toJSON()
151
+ : [];
152
+ const merged = [...existing, ...additions];
153
+ const [start, valueEnd] = isSeq(sequence)
154
+ ? nodeRange(sequence)
155
+ : nodeRange(pair.value);
156
+ if (isSeq(sequence) && sequence.flow) {
157
+ const flow = stringify(merged, {
158
+ collectionStyle: 'flow',
159
+ lineWidth: 0,
160
+ }).trimEnd();
161
+ return splice(source, start, valueEnd, flow);
162
+ }
163
+ return splice(source, start, valueEnd, `\n${sequenceEntries(merged, indent + 2)}`);
164
+ };
165
+ // Retraction (#115): delete the field's whole entry, from the start of its
166
+ // key line through the end of its value's last line.
167
+ const removeField = (source, map, key) => {
168
+ const pair = pairFor(map, key);
169
+ if (pair === undefined)
170
+ return undefined;
171
+ const start = lineStartOf(source, nodeRange(pair.key)[0]);
172
+ const valueEnd = pair.value === null || pair.value === undefined
173
+ ? nodeRange(pair.key)[2]
174
+ : nodeRange(pair.value)[2];
175
+ return splice(source, start, lineEndAfter(source, valueEnd), '');
176
+ };
177
+ // ---------------------------------------------------------------------------
178
+ export function runApplyCommand(options, cwd) {
179
+ const json = options.includes('--json');
180
+ const rest = options.filter((option) => option !== '--json');
181
+ const [operationsPath, workspacePath] = rest;
182
+ if (rest.length !== 2 ||
183
+ operationsPath === undefined ||
184
+ workspacePath === undefined ||
185
+ rest.some((option) => option.startsWith('-'))) {
186
+ return { exitCode: 2, stdout: '', stderr: usage };
187
+ }
188
+ try {
189
+ const manifestSource = readFileSync(resolve(cwd, workspacePath), 'utf8');
190
+ if (parseDocument(manifestSource).get('format') !== 'yarramate/workspace/v1') {
191
+ return {
192
+ exitCode: 2,
193
+ stdout: '',
194
+ stderr: 'apply requires an explicit workspace manifest (yarramate/workspace/v1)\n',
195
+ };
196
+ }
197
+ const failed = (diagnostics) => ({
198
+ exitCode: 1,
199
+ stdout: json ? diagnosticJson(diagnostics) : humanDiagnostics(diagnostics),
200
+ stderr: '',
201
+ });
202
+ const loadedWorkspace = loadWorkspaceManifest({ path: workspacePath, source: manifestSource }, cwd);
203
+ if (!loadedWorkspace.ok)
204
+ return failed(loadedWorkspace.diagnostics);
205
+ const workspace = loadedWorkspace.workspace;
206
+ const operationsSource = readFileSync(resolve(cwd, operationsPath), 'utf8');
207
+ const loadedOperations = loadSourceDocument({ path: operationsPath, source: operationsSource }, validateOperations, 'Operations');
208
+ if (!loadedOperations.ok)
209
+ return failed(loadedOperations.diagnostics);
210
+ const operations = loadedOperations.document.value.operations;
211
+ const yaml = loadedOperations.document.yaml;
212
+ const lineCounter = loadedOperations.document.lineCounter;
213
+ // Documents are addressed by their manifest paths; an operation aimed
214
+ // anywhere else is rejected before anything is touched.
215
+ const workspaceDocuments = new Map(workspace.documents.map((path) => [resolve(cwd, path), path]));
216
+ const candidates = new Map();
217
+ const counts = {
218
+ addedConcepts: 0,
219
+ addedRelationships: 0,
220
+ updatedConcepts: 0,
221
+ updatedRelationships: 0,
222
+ };
223
+ for (const [index, operation] of operations.entries()) {
224
+ const absolute = resolve(cwd, operation.document);
225
+ const manifestPath = workspaceDocuments.get(absolute);
226
+ const locate = (message) => ({
227
+ severity: 'error',
228
+ code: 'YM912',
229
+ message,
230
+ ...locateSourcePath(operationsPath, yaml, lineCounter, ['operations', index, 'document'], `/operations/${index}/document`),
231
+ });
232
+ if (manifestPath === undefined) {
233
+ return failed([
234
+ locate(`Operation ${index} targets "${operation.document}", which is not a document of workspace "${workspace.id}"`),
235
+ ]);
236
+ }
237
+ let source = candidates.get(absolute);
238
+ if (source === undefined) {
239
+ source = readFileSync(absolute, 'utf8');
240
+ }
241
+ if (operation.op === 'add-concept') {
242
+ source = appendCollectionItem(source, 'concepts', operation.concept);
243
+ counts.addedConcepts += 1;
244
+ }
245
+ else if (operation.op === 'add-relationship') {
246
+ source = appendCollectionItem(source, 'relationships', operation.relationship);
247
+ counts.addedRelationships += 1;
248
+ }
249
+ else {
250
+ const collection = operation.op === 'update-concept' ? 'concepts' : 'relationships';
251
+ const payload = (operation.op === 'update-concept'
252
+ ? operation.concept
253
+ : operation.relationship);
254
+ const scalars = operation.op === 'update-concept'
255
+ ? SCALAR_CONCEPT_FIELDS
256
+ : SCALAR_RELATIONSHIP_FIELDS;
257
+ const lists = operation.op === 'update-concept'
258
+ ? LIST_CONCEPT_FIELDS
259
+ : LIST_RELATIONSHIP_FIELDS;
260
+ const id = payload.id;
261
+ const removals = operation.remove ?? [];
262
+ const contradiction = removals.find((key) => payload[key] !== undefined);
263
+ if (contradiction !== undefined) {
264
+ return failed([
265
+ locate(`Operation ${index} both sets and removes "${contradiction}" on "${id}"`),
266
+ ]);
267
+ }
268
+ const located = itemMap(source, collection, id);
269
+ if (located === undefined) {
270
+ return failed([
271
+ locate(`Operation ${index} updates "${id}", which does not exist in ${operation.document}`),
272
+ ]);
273
+ }
274
+ for (const key of scalars) {
275
+ if (payload[key] === undefined)
276
+ continue;
277
+ source = setScalarField(source, itemMap(source, collection, id).map, key, payload[key]);
278
+ }
279
+ for (const key of lists) {
280
+ const additions = payload[key];
281
+ if (additions === undefined || additions.length === 0)
282
+ continue;
283
+ source = appendListField(source, itemMap(source, collection, id).map, key, additions);
284
+ }
285
+ for (const key of removals) {
286
+ const removed = removeField(source, itemMap(source, collection, id).map, key);
287
+ if (removed === undefined) {
288
+ return failed([
289
+ locate(`Operation ${index} removes "${key}", which is not set on "${id}"`),
290
+ ]);
291
+ }
292
+ source = removed;
293
+ }
294
+ if (operation.op === 'update-concept') {
295
+ counts.updatedConcepts += 1;
296
+ }
297
+ else {
298
+ counts.updatedRelationships += 1;
299
+ }
300
+ }
301
+ candidates.set(absolute, source);
302
+ }
303
+ // The atomic gate: the whole candidate workspace must compile before a
304
+ // single byte is written; any diagnostic rejects the entire batch.
305
+ const compilation = compileWorkspace([...workspace.profiles, ...workspace.documents].map((path) => {
306
+ const absolute = resolve(cwd, path);
307
+ return {
308
+ path,
309
+ source: candidates.get(absolute) ?? readFileSync(absolute, 'utf8'),
310
+ };
311
+ }));
312
+ if (!compilation.ok)
313
+ return failed(compilation.diagnostics);
314
+ for (const [absolute, source] of candidates) {
315
+ writeFileSync(absolute, source, 'utf8');
316
+ }
317
+ const touched = [...candidates.keys()]
318
+ .map((absolute) => workspaceDocuments.get(absolute))
319
+ .sort();
320
+ if (json) {
321
+ return {
322
+ exitCode: 0,
323
+ stdout: `${JSON.stringify({
324
+ format: 'yarramate/apply-result/v1',
325
+ workspace: workspace.id,
326
+ applied: counts,
327
+ documents: touched,
328
+ }, null, 2)}\n`,
329
+ stderr: '',
330
+ };
331
+ }
332
+ const applied = counts.addedConcepts +
333
+ counts.addedRelationships +
334
+ counts.updatedConcepts +
335
+ counts.updatedRelationships;
336
+ return {
337
+ exitCode: 0,
338
+ stdout: `Applied ${applied} operation${applied === 1 ? '' : 's'} to ${touched.join(', ')}\n`,
339
+ stderr: '',
340
+ };
341
+ }
342
+ catch (error) {
343
+ const message = error instanceof Error ? error.message : String(error);
344
+ return { exitCode: 2, stdout: '', stderr: `${message}\n` };
345
+ }
346
+ }
@@ -1,2 +1,2 @@
1
1
  import { type CliResult } from './cli-support.js';
2
- export declare function runNewCommand(options: readonly string[], cwd: string): CliResult;
2
+ export declare function runAskCommand(options: readonly string[], cwd: string): CliResult;