@orkestrel/brief 0.0.6 → 0.0.8
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 +26 -12
- package/dist/src/core/index.cjs +465 -279
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +907 -631
- package/dist/src/core/index.d.ts +907 -631
- package/dist/src/core/index.js +454 -268
- package/dist/src/core/index.js.map +1 -1
- package/package.json +18 -18
package/dist/src/core/index.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { andOf, arrayOf, arrayShape, attempt, booleanShape, boundsOf, cloneJSONRecord, createContract, integerShape, isBoolean, isInteger, isNonEmptyString, isString, literalOf, literalShape, objectShape, optionalShape, parseJSONAs, recordOf, stringShape } from "@orkestrel/contract";
|
|
2
2
|
import { canonicalize, collapseWhitespace, createInterpret, digestValue, isInterpretation } from "@orkestrel/interpret";
|
|
3
|
-
import {
|
|
3
|
+
import { createAtom, createCompound, createLogicalDefinition, createLogicalReasoner, createReason, createRule, formatField, isLogicalResult } from "@orkestrel/reason";
|
|
4
4
|
import { Emitter } from "@orkestrel/emitter";
|
|
5
5
|
//#region src/core/constants.ts
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Lists the `TaskOperation` values, frozen.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Compose the tuple rather than restating its members: `literalOf(TASK_OPERATIONS)` builds the
|
|
11
|
+
* guard and `parseEnum(value, TASK_OPERATIONS)` coerces a bare value against it.
|
|
12
|
+
*/
|
|
7
13
|
var TASK_OPERATIONS = Object.freeze([
|
|
8
14
|
"create",
|
|
9
15
|
"refactor",
|
|
@@ -18,7 +24,7 @@ var TASK_OPERATIONS = Object.freeze([
|
|
|
18
24
|
"document",
|
|
19
25
|
"plan"
|
|
20
26
|
]);
|
|
21
|
-
/**
|
|
27
|
+
/** Lists the `TaskDomain` values, frozen. */
|
|
22
28
|
var TASK_DOMAINS = Object.freeze([
|
|
23
29
|
"code",
|
|
24
30
|
"writing",
|
|
@@ -29,7 +35,7 @@ var TASK_DOMAINS = Object.freeze([
|
|
|
29
35
|
"ops",
|
|
30
36
|
"other"
|
|
31
37
|
]);
|
|
32
|
-
/**
|
|
38
|
+
/** Lists the `OutputFormat` values, frozen. */
|
|
33
39
|
var OUTPUT_FORMATS = Object.freeze([
|
|
34
40
|
"markdown",
|
|
35
41
|
"json",
|
|
@@ -37,14 +43,14 @@ var OUTPUT_FORMATS = Object.freeze([
|
|
|
37
43
|
"diff",
|
|
38
44
|
"prose"
|
|
39
45
|
]);
|
|
40
|
-
/**
|
|
46
|
+
/** Lists the `RiskSeverity` values, frozen. */
|
|
41
47
|
var RISK_SEVERITIES = Object.freeze([
|
|
42
48
|
"low",
|
|
43
49
|
"medium",
|
|
44
50
|
"high"
|
|
45
51
|
]);
|
|
46
52
|
/**
|
|
47
|
-
*
|
|
53
|
+
* Lists every published `Interpretation` member name, frozen.
|
|
48
54
|
*
|
|
49
55
|
* @remarks
|
|
50
56
|
* The capture list `BriefCompiler` hands `captureValue` at each interpret door — the borrowed
|
|
@@ -69,33 +75,32 @@ var INTERPRETATION_MEMBERS = Object.freeze([
|
|
|
69
75
|
"prompt",
|
|
70
76
|
"stages",
|
|
71
77
|
"failures",
|
|
72
|
-
"complete",
|
|
73
78
|
"confidence",
|
|
74
79
|
"digest"
|
|
75
80
|
]);
|
|
76
81
|
/**
|
|
77
|
-
* `16` — the default turn cap `briefToGoal` renders.
|
|
82
|
+
* Holds `16` — the default turn cap `briefToGoal` renders.
|
|
78
83
|
*
|
|
79
84
|
* @remarks
|
|
80
85
|
* Domain-qualified so the barrel stays collision-free as sibling modules add their own
|
|
81
86
|
* turn defaults.
|
|
82
87
|
*/
|
|
83
88
|
var DEFAULT_BRIEF_TURNS = 16;
|
|
84
|
-
/** `'gate'` — the id of the `
|
|
89
|
+
/** Holds `'gate'` — the id of the `buildGateDefinition()` logical definition. */
|
|
85
90
|
var GATE_ID = "gate";
|
|
86
91
|
/**
|
|
87
|
-
*
|
|
92
|
+
* Matches every line terminator a brief field refuses.
|
|
88
93
|
*
|
|
89
94
|
* @remarks
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
95
|
+
* Every ECMAScript line terminator, not only `\n`: a renderer that splits on any of them
|
|
96
|
+
* would let the others forge a markdown row. CRLF leads the alternation so a Windows
|
|
97
|
+
* exemplar splits as ONE break rather than two, which would insert a blank line the caller
|
|
98
|
+
* never wrote. Kept unanchored and stateless — no `g` flag — so `test` never carries
|
|
94
99
|
* `lastIndex` between calls.
|
|
95
100
|
*/
|
|
96
101
|
var LINE_BREAK_PATTERN = /\r\n|[\n\r\u2028\u2029]/;
|
|
97
102
|
/**
|
|
98
|
-
*
|
|
103
|
+
* Holds the positive form of {@link LINE_BREAK_PATTERN}, for a `stringShape` `pattern`.
|
|
99
104
|
*
|
|
100
105
|
* @remarks
|
|
101
106
|
* `stringShape`'s `pattern` must MATCH an accepted value, so the guard's refusal regex
|
|
@@ -104,7 +109,7 @@ var LINE_BREAK_PATTERN = /\r\n|[\n\r\u2028\u2029]/;
|
|
|
104
109
|
*/
|
|
105
110
|
var SINGLE_LINE_PATTERN = /^[^\n\r\u2028\u2029]*$/;
|
|
106
111
|
/**
|
|
107
|
-
*
|
|
112
|
+
* Matches a string of one or more spaces and nothing else.
|
|
108
113
|
*
|
|
109
114
|
* @remarks
|
|
110
115
|
* The one exemplar side `exampleToLines` must NOT pad. CommonMark strips a fully-blank code
|
|
@@ -118,9 +123,12 @@ var BLANK_PATTERN = /^ +$/;
|
|
|
118
123
|
//#endregion
|
|
119
124
|
//#region src/core/errors.ts
|
|
120
125
|
/**
|
|
121
|
-
*
|
|
126
|
+
* Represents the one error class this package throws.
|
|
122
127
|
*
|
|
123
128
|
* @remarks
|
|
129
|
+
* Extends `Error` with a readonly `code` on the `BriefErrorCode` vocabulary and an optional
|
|
130
|
+
* readonly `context` record carrying whatever the raising site can supply.
|
|
131
|
+
*
|
|
124
132
|
* Throws are reserved for caller misuse: `assertBrief`, `snapshotBrief`, and `pinBrief` on
|
|
125
133
|
* off-contract data throw `INVALID`; any method after `destroy()` throws `DESTROYED`; and `BriefCompiler.gate` throws
|
|
126
134
|
* `GATE_FAILED` when a borrowed reasoner returns a non-logical result. A stage that fails
|
|
@@ -148,10 +156,10 @@ var BriefError = class extends Error {
|
|
|
148
156
|
}
|
|
149
157
|
};
|
|
150
158
|
/**
|
|
151
|
-
*
|
|
159
|
+
* Narrows a caught value to a {@link BriefError}.
|
|
152
160
|
*
|
|
153
161
|
* @param value - The caught value to inspect.
|
|
154
|
-
* @returns
|
|
162
|
+
* @returns True if `value` is a `BriefError`; false otherwise.
|
|
155
163
|
*
|
|
156
164
|
* @example
|
|
157
165
|
* ```ts
|
|
@@ -169,82 +177,100 @@ function isBriefError(value) {
|
|
|
169
177
|
}
|
|
170
178
|
//#endregion
|
|
171
179
|
//#region src/core/shapers.ts
|
|
172
|
-
/**
|
|
180
|
+
/** Describes a single-line string of any length, including empty — the shape mirror of `isText`. */
|
|
173
181
|
var textShape = stringShape({ pattern: SINGLE_LINE_PATTERN });
|
|
174
|
-
/**
|
|
182
|
+
/** Describes a non-empty single-line string — the shape mirror of `isLine`. */
|
|
175
183
|
var lineShape = stringShape({
|
|
176
184
|
min: 1,
|
|
177
185
|
pattern: SINGLE_LINE_PATTERN
|
|
178
186
|
});
|
|
179
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* Describes the `Task` shape — closed operation and domain vocabularies plus a non-empty
|
|
189
|
+
* statement.
|
|
190
|
+
*
|
|
191
|
+
* @remarks
|
|
192
|
+
* `literalShape(TASK_OPERATIONS)` and `literalShape(TASK_DOMAINS)` compile the same tuples the
|
|
193
|
+
* guards read, and `statement` carries `min: 1`.
|
|
194
|
+
*/
|
|
180
195
|
var taskShape = objectShape({
|
|
181
196
|
operation: literalShape(TASK_OPERATIONS),
|
|
182
197
|
domain: literalShape(TASK_DOMAINS),
|
|
183
198
|
statement: lineShape
|
|
184
199
|
}, { description: "What the brief asks for, in one imperative sentence." });
|
|
185
|
-
/**
|
|
200
|
+
/** Describes the `Reference` shape — a path and the note that justifies listing it. */
|
|
186
201
|
var referenceShape = objectShape({
|
|
187
202
|
path: lineShape,
|
|
188
203
|
note: lineShape
|
|
189
204
|
}, { description: "One referenced path and why it is listed." });
|
|
190
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* Describes the `Manifest` shape — disjoint reference partitions.
|
|
207
|
+
*
|
|
208
|
+
* @remarks
|
|
209
|
+
* Each partition is an `arrayShape(referenceShape)`; disjointness is `validateBrief`'s pass
|
|
210
|
+
* rather than the shape's.
|
|
211
|
+
*/
|
|
191
212
|
var manifestShape = objectShape({
|
|
192
213
|
read: arrayShape(referenceShape),
|
|
193
214
|
edit: arrayShape(referenceShape),
|
|
194
215
|
locked: arrayShape(referenceShape),
|
|
195
216
|
forbidden: arrayShape(referenceShape)
|
|
196
|
-
}, { description: "The
|
|
197
|
-
/**
|
|
217
|
+
}, { description: "The disjoint file partitions of a brief." });
|
|
218
|
+
/**
|
|
219
|
+
* Describes the `Outcome` shape — a one-based rank, the result text, and whether it gates done.
|
|
220
|
+
*
|
|
221
|
+
* @remarks
|
|
222
|
+
* `rank` is an `integerShape({ min: 1 })`, so a zero or fractional rank is off-contract.
|
|
223
|
+
*/
|
|
198
224
|
var outcomeShape = objectShape({
|
|
199
225
|
rank: integerShape({ min: 1 }),
|
|
200
226
|
text: lineShape,
|
|
201
227
|
required: booleanShape()
|
|
202
228
|
}, { description: "One ranked outcome — a result, never a step." });
|
|
203
|
-
/**
|
|
229
|
+
/** Describes the `Given` shape — one categorized context fact. */
|
|
204
230
|
var givenShape = objectShape({
|
|
205
231
|
category: lineShape,
|
|
206
232
|
name: lineShape,
|
|
207
233
|
value: textShape
|
|
208
234
|
}, { description: "One context fact handed to the executor." });
|
|
209
|
-
/**
|
|
235
|
+
/** Describes the `Example` shape — one input to output exemplar. */
|
|
210
236
|
var exampleShape = objectShape({
|
|
211
237
|
input: stringShape({ min: 1 }),
|
|
212
238
|
output: stringShape({ min: 1 }),
|
|
213
239
|
note: optionalShape(lineShape)
|
|
214
240
|
}, { description: "One input to output exemplar." });
|
|
215
|
-
/**
|
|
241
|
+
/** Describes the `Citation` shape — a name, a locator, and why the source is cited. */
|
|
216
242
|
var citationShape = objectShape({
|
|
217
243
|
name: lineShape,
|
|
218
244
|
url: lineShape,
|
|
219
245
|
note: lineShape
|
|
220
246
|
}, { description: "One external source; list order is the trust order." });
|
|
221
|
-
/**
|
|
247
|
+
/** Describes the `Gap` shape — an unknown, whether it blocks, and the candidates that would close it. */
|
|
222
248
|
var gapShape = objectShape({
|
|
223
249
|
field: lineShape,
|
|
224
250
|
question: lineShape,
|
|
225
251
|
blocking: booleanShape(),
|
|
226
252
|
candidates: optionalShape(arrayShape(lineShape))
|
|
227
253
|
}, { description: "One unresolved decision; blocking means the gate fails closed." });
|
|
228
|
-
/**
|
|
254
|
+
/** Describes the `Risk` shape — a closed severity, the risk, and its mitigation. */
|
|
229
255
|
var riskShape = objectShape({
|
|
230
256
|
severity: literalShape(RISK_SEVERITIES),
|
|
231
257
|
text: lineShape,
|
|
232
258
|
mitigation: lineShape
|
|
233
259
|
}, { description: "One pre-empted risk and the mitigation that answers it." });
|
|
234
|
-
/**
|
|
260
|
+
/** Describes the `Output` shape — a closed format plus its optional refinements. */
|
|
235
261
|
var outputShape = objectShape({
|
|
236
262
|
format: literalShape(OUTPUT_FORMATS),
|
|
237
263
|
sections: optionalShape(arrayShape(lineShape)),
|
|
238
264
|
include: optionalShape(arrayShape(lineShape)),
|
|
239
265
|
exclude: optionalShape(arrayShape(lineShape))
|
|
240
266
|
}, { description: "The closed shape of the deliverable." });
|
|
241
|
-
/**
|
|
267
|
+
/** Describes the `Proof` shape — the claim and the command that settles it. */
|
|
242
268
|
var proofShape = objectShape({
|
|
243
269
|
text: lineShape,
|
|
244
270
|
command: lineShape
|
|
245
271
|
}, { description: "One mechanical, transcript-provable check." });
|
|
246
272
|
/**
|
|
247
|
-
*
|
|
273
|
+
* Describes the whole `Brief` shape, section shapes composed.
|
|
248
274
|
*
|
|
249
275
|
* @remarks
|
|
250
276
|
* `trace` and `hash` are optional because `pinBrief` fills them; an unpinned draft is
|
|
@@ -271,40 +297,86 @@ var briefShape = objectShape({
|
|
|
271
297
|
//#endregion
|
|
272
298
|
//#region src/core/validators.ts
|
|
273
299
|
/**
|
|
274
|
-
*
|
|
300
|
+
* Checks whether the value is a string holding no line terminator, empty included.
|
|
275
301
|
*
|
|
276
302
|
* @remarks
|
|
277
303
|
* `briefToMarkdown` renders each brief field as ONE markdown row, so a field carrying a
|
|
278
304
|
* line break would forge a heading or an extra manifest row — which is how a rendered
|
|
279
305
|
* prompt and `briefToDispatch`'s path sets could disagree about the same brief.
|
|
306
|
+
*
|
|
307
|
+
* @param value - The value to inspect.
|
|
308
|
+
* @returns True if `value` is a string holding no line terminator, empty included; false
|
|
309
|
+
* otherwise.
|
|
280
310
|
*/
|
|
281
311
|
var isText = (value) => isString(value) && !LINE_BREAK_PATTERN.test(value);
|
|
282
|
-
/**
|
|
312
|
+
/**
|
|
313
|
+
* Checks whether the value is a non-empty string holding no line terminator.
|
|
314
|
+
*
|
|
315
|
+
* @remarks
|
|
316
|
+
* The shape of nearly every brief field: a path, a note, a statement, a rule, and a command
|
|
317
|
+
* all narrow through it.
|
|
318
|
+
*
|
|
319
|
+
* @param value - The value to inspect.
|
|
320
|
+
* @returns True if `value` is a non-empty string holding no line terminator; false otherwise.
|
|
321
|
+
*/
|
|
283
322
|
var isLine = andOf(isNonEmptyString, isText);
|
|
284
|
-
/**
|
|
323
|
+
/**
|
|
324
|
+
* Checks whether the value is one of the `TaskOperation` literals.
|
|
325
|
+
*
|
|
326
|
+
* @param value - The value to inspect.
|
|
327
|
+
* @returns True if `value` is one of the `TaskOperation` literals; false otherwise.
|
|
328
|
+
*/
|
|
285
329
|
var isTaskOperation = literalOf(TASK_OPERATIONS);
|
|
286
|
-
/**
|
|
330
|
+
/**
|
|
331
|
+
* Checks whether the value is one of the `TaskDomain` literals.
|
|
332
|
+
*
|
|
333
|
+
* @param value - The value to inspect.
|
|
334
|
+
* @returns True if `value` is one of the `TaskDomain` literals; false otherwise.
|
|
335
|
+
*/
|
|
287
336
|
var isTaskDomain = literalOf(TASK_DOMAINS);
|
|
288
|
-
/**
|
|
337
|
+
/**
|
|
338
|
+
* Checks whether the value is one of the `OutputFormat` literals.
|
|
339
|
+
*
|
|
340
|
+
* @param value - The value to inspect.
|
|
341
|
+
* @returns True if `value` is one of the `OutputFormat` literals; false otherwise.
|
|
342
|
+
*/
|
|
289
343
|
var isOutputFormat = literalOf(OUTPUT_FORMATS);
|
|
290
|
-
/**
|
|
344
|
+
/**
|
|
345
|
+
* Checks whether the value is one of the `RiskSeverity` literals.
|
|
346
|
+
*
|
|
347
|
+
* @param value - The value to inspect.
|
|
348
|
+
* @returns True if `value` is one of the `RiskSeverity` literals; false otherwise.
|
|
349
|
+
*/
|
|
291
350
|
var isRiskSeverity = literalOf(RISK_SEVERITIES);
|
|
292
|
-
/**
|
|
351
|
+
/**
|
|
352
|
+
* Checks whether the value is a well-formed `Task` — both vocabularies closed, statement one line.
|
|
353
|
+
*
|
|
354
|
+
* @param value - The value to inspect.
|
|
355
|
+
* @returns True if `value` is a well-formed `Task`; false otherwise.
|
|
356
|
+
*/
|
|
293
357
|
var isTask = recordOf({
|
|
294
358
|
operation: isTaskOperation,
|
|
295
359
|
domain: isTaskDomain,
|
|
296
360
|
statement: isLine
|
|
297
361
|
});
|
|
298
|
-
/**
|
|
362
|
+
/**
|
|
363
|
+
* Checks whether the value is a well-formed `Reference` — both members required, both single-line.
|
|
364
|
+
*
|
|
365
|
+
* @param value - The value to inspect.
|
|
366
|
+
* @returns True if `value` is a well-formed `Reference`; false otherwise.
|
|
367
|
+
*/
|
|
299
368
|
var isReference = recordOf({
|
|
300
369
|
path: isLine,
|
|
301
370
|
note: isLine
|
|
302
371
|
});
|
|
303
372
|
/**
|
|
304
|
-
*
|
|
373
|
+
* Checks whether the value is a well-formed `Manifest`.
|
|
305
374
|
*
|
|
306
375
|
* @remarks
|
|
307
376
|
* Partition presence only — disjointness is `validateBrief`'s semantic pass.
|
|
377
|
+
*
|
|
378
|
+
* @param value - The value to inspect.
|
|
379
|
+
* @returns True if `value` is a well-formed `Manifest`; false otherwise.
|
|
308
380
|
*/
|
|
309
381
|
var isManifest = recordOf({
|
|
310
382
|
read: arrayOf(isReference),
|
|
@@ -312,50 +384,83 @@ var isManifest = recordOf({
|
|
|
312
384
|
locked: arrayOf(isReference),
|
|
313
385
|
forbidden: arrayOf(isReference)
|
|
314
386
|
});
|
|
315
|
-
/**
|
|
387
|
+
/**
|
|
388
|
+
* Checks whether the value is a well-formed `Outcome` — `rank` a positive integer.
|
|
389
|
+
*
|
|
390
|
+
* @param value - The value to inspect.
|
|
391
|
+
* @returns True if `value` is a well-formed `Outcome`; false otherwise.
|
|
392
|
+
*/
|
|
316
393
|
var isOutcome = recordOf({
|
|
317
394
|
rank: andOf(isInteger, boundsOf(1)),
|
|
318
395
|
text: isLine,
|
|
319
396
|
required: isBoolean
|
|
320
397
|
});
|
|
321
|
-
/**
|
|
398
|
+
/**
|
|
399
|
+
* Checks whether the value is a well-formed `Given` — its `value` may be empty but stays one line.
|
|
400
|
+
*
|
|
401
|
+
* @param value - The value to inspect.
|
|
402
|
+
* @returns True if `value` is a well-formed `Given`; false otherwise.
|
|
403
|
+
*/
|
|
322
404
|
var isGiven = recordOf({
|
|
323
405
|
category: isLine,
|
|
324
406
|
name: isLine,
|
|
325
407
|
value: isText
|
|
326
408
|
});
|
|
327
409
|
/**
|
|
328
|
-
*
|
|
410
|
+
* Checks whether the value is a well-formed `Example`.
|
|
329
411
|
*
|
|
330
412
|
* @remarks
|
|
331
413
|
* An exemplar's two sides are the ONLY members a brief lets span lines, because they
|
|
332
414
|
* carry code. `briefToMarkdown` fences them rather than rendering them as a row.
|
|
415
|
+
*
|
|
416
|
+
* @param value - The value to inspect.
|
|
417
|
+
* @returns True if `value` is a well-formed `Example`; false otherwise.
|
|
333
418
|
*/
|
|
334
419
|
var isExample = recordOf({
|
|
335
420
|
input: isNonEmptyString,
|
|
336
421
|
output: isNonEmptyString,
|
|
337
422
|
note: isLine
|
|
338
423
|
}, ["note"]);
|
|
339
|
-
/**
|
|
424
|
+
/**
|
|
425
|
+
* Checks whether the value is a well-formed `Citation` — every member single-line.
|
|
426
|
+
*
|
|
427
|
+
* @param value - The value to inspect.
|
|
428
|
+
* @returns True if `value` is a well-formed `Citation`; false otherwise.
|
|
429
|
+
*/
|
|
340
430
|
var isCitation = recordOf({
|
|
341
431
|
name: isLine,
|
|
342
432
|
url: isLine,
|
|
343
433
|
note: isLine
|
|
344
434
|
});
|
|
345
|
-
/**
|
|
435
|
+
/**
|
|
436
|
+
* Checks whether the value is a well-formed `Gap`.
|
|
437
|
+
*
|
|
438
|
+
* @param value - The value to inspect.
|
|
439
|
+
* @returns True if `value` is a well-formed `Gap`; false otherwise.
|
|
440
|
+
*/
|
|
346
441
|
var isGap = recordOf({
|
|
347
442
|
field: isLine,
|
|
348
443
|
question: isLine,
|
|
349
444
|
blocking: isBoolean,
|
|
350
445
|
candidates: arrayOf(isLine)
|
|
351
446
|
}, ["candidates"]);
|
|
352
|
-
/**
|
|
447
|
+
/**
|
|
448
|
+
* Checks whether the value is a well-formed `Risk` — `severity` on the closed vocabulary.
|
|
449
|
+
*
|
|
450
|
+
* @param value - The value to inspect.
|
|
451
|
+
* @returns True if `value` is a well-formed `Risk`; false otherwise.
|
|
452
|
+
*/
|
|
353
453
|
var isRisk = recordOf({
|
|
354
454
|
severity: isRiskSeverity,
|
|
355
455
|
text: isLine,
|
|
356
456
|
mitigation: isLine
|
|
357
457
|
});
|
|
358
|
-
/**
|
|
458
|
+
/**
|
|
459
|
+
* Checks whether the value is a well-formed `Output` — `format` on the closed vocabulary.
|
|
460
|
+
*
|
|
461
|
+
* @param value - The value to inspect.
|
|
462
|
+
* @returns True if `value` is a well-formed `Output`; false otherwise.
|
|
463
|
+
*/
|
|
359
464
|
var isOutput = recordOf({
|
|
360
465
|
format: isOutputFormat,
|
|
361
466
|
sections: arrayOf(isLine),
|
|
@@ -366,17 +471,25 @@ var isOutput = recordOf({
|
|
|
366
471
|
"include",
|
|
367
472
|
"exclude"
|
|
368
473
|
]);
|
|
369
|
-
/**
|
|
474
|
+
/**
|
|
475
|
+
* Checks whether the value is a well-formed `Proof`.
|
|
476
|
+
*
|
|
477
|
+
* @param value - The value to inspect.
|
|
478
|
+
* @returns True if `value` is a well-formed `Proof`; false otherwise.
|
|
479
|
+
*/
|
|
370
480
|
var isProof = recordOf({
|
|
371
481
|
text: isLine,
|
|
372
482
|
command: isLine
|
|
373
483
|
});
|
|
374
484
|
/**
|
|
375
|
-
*
|
|
485
|
+
* Checks whether the value satisfies the whole exact-record `Brief` contract.
|
|
376
486
|
*
|
|
377
487
|
* @remarks
|
|
378
488
|
* Every section must be present; an extra key fails. `trace` and `hash` are the only
|
|
379
489
|
* optional members, because `pinBrief` rather than the author fills them.
|
|
490
|
+
*
|
|
491
|
+
* @param value - The value to inspect.
|
|
492
|
+
* @returns True if `value` satisfies the whole exact-record `Brief` contract; false otherwise.
|
|
380
493
|
*/
|
|
381
494
|
var isBrief = recordOf({
|
|
382
495
|
task: isTask,
|
|
@@ -477,7 +590,7 @@ function captureValue(source, members) {
|
|
|
477
590
|
return target;
|
|
478
591
|
}
|
|
479
592
|
/**
|
|
480
|
-
*
|
|
593
|
+
* Returns a deeply owned, deeply frozen copy of a brief, refusing anything off-contract.
|
|
481
594
|
*
|
|
482
595
|
* @remarks
|
|
483
596
|
* The one reading boundary this package has, used by the pin, the registry, and every
|
|
@@ -501,10 +614,10 @@ function captureValue(source, members) {
|
|
|
501
614
|
*
|
|
502
615
|
* @example
|
|
503
616
|
* ```ts
|
|
504
|
-
* import {
|
|
617
|
+
* import { buildBrief, buildOutcome, buildTask, snapshotBrief } from '@orkestrel/brief'
|
|
505
618
|
*
|
|
506
|
-
* const outcomes = [
|
|
507
|
-
* const owned = snapshotBrief(
|
|
619
|
+
* const outcomes = [buildOutcome(1, 'shipped')]
|
|
620
|
+
* const owned = snapshotBrief(buildBrief(buildTask('plan', 'ops', 'Plan the release.'), { outcomes }))
|
|
508
621
|
* owned.outcomes === outcomes // false — the alias is broken
|
|
509
622
|
* Object.isFrozen(owned.outcomes) // true
|
|
510
623
|
* ```
|
|
@@ -517,7 +630,7 @@ function snapshotBrief(source) {
|
|
|
517
630
|
//#endregion
|
|
518
631
|
//#region src/core/helpers.ts
|
|
519
632
|
/**
|
|
520
|
-
*
|
|
633
|
+
* Assembles a `Task` from an operation, a domain, and a statement.
|
|
521
634
|
*
|
|
522
635
|
* @param operation - What the brief asks for, from the closed operation vocabulary.
|
|
523
636
|
* @param domain - The subject matter, from the closed domain vocabulary.
|
|
@@ -526,12 +639,12 @@ function snapshotBrief(source) {
|
|
|
526
639
|
*
|
|
527
640
|
* @example
|
|
528
641
|
* ```ts
|
|
529
|
-
* import {
|
|
642
|
+
* import { buildTask } from '@orkestrel/brief'
|
|
530
643
|
*
|
|
531
|
-
*
|
|
644
|
+
* buildTask('refactor', 'code', 'Refactor useForm to native browser form APIs.')
|
|
532
645
|
* ```
|
|
533
646
|
*/
|
|
534
|
-
function
|
|
647
|
+
function buildTask(operation, domain, statement) {
|
|
535
648
|
return {
|
|
536
649
|
operation,
|
|
537
650
|
domain,
|
|
@@ -539,7 +652,11 @@ function task(operation, domain, statement) {
|
|
|
539
652
|
};
|
|
540
653
|
}
|
|
541
654
|
/**
|
|
542
|
-
*
|
|
655
|
+
* Assembles a `Reference` from a path and the note that justifies listing it.
|
|
656
|
+
*
|
|
657
|
+
* @remarks
|
|
658
|
+
* The one builder for an authority entry and a manifest entry alike: the container the record
|
|
659
|
+
* lands in is what says whether the path is ranked or permitted.
|
|
543
660
|
*
|
|
544
661
|
* @param path - The referenced path or glob.
|
|
545
662
|
* @param note - Why the path is listed.
|
|
@@ -547,31 +664,31 @@ function task(operation, domain, statement) {
|
|
|
547
664
|
*
|
|
548
665
|
* @example
|
|
549
666
|
* ```ts
|
|
550
|
-
* import {
|
|
667
|
+
* import { buildReference } from '@orkestrel/brief'
|
|
551
668
|
*
|
|
552
|
-
*
|
|
669
|
+
* buildReference('AGENTS.md', 'project law') // { path: 'AGENTS.md', note: 'project law' }
|
|
553
670
|
* ```
|
|
554
671
|
*/
|
|
555
|
-
function
|
|
672
|
+
function buildReference(path, note) {
|
|
556
673
|
return {
|
|
557
674
|
path,
|
|
558
675
|
note
|
|
559
676
|
};
|
|
560
677
|
}
|
|
561
678
|
/**
|
|
562
|
-
*
|
|
679
|
+
* Assembles a `Manifest`, defaulting every absent partition to an empty list.
|
|
563
680
|
*
|
|
564
681
|
* @param partitions - The partitions to fill; a partial literal is enough.
|
|
565
|
-
* @returns A fresh `Manifest` with
|
|
682
|
+
* @returns A fresh `Manifest` with every partition present.
|
|
566
683
|
*
|
|
567
684
|
* @example
|
|
568
685
|
* ```ts
|
|
569
|
-
* import {
|
|
686
|
+
* import { buildManifest, buildReference } from '@orkestrel/brief'
|
|
570
687
|
*
|
|
571
|
-
*
|
|
688
|
+
* buildManifest({ edit: [buildReference('src/core/helpers.ts', 'implementation')] })
|
|
572
689
|
* ```
|
|
573
690
|
*/
|
|
574
|
-
function
|
|
691
|
+
function buildManifest(partitions) {
|
|
575
692
|
return {
|
|
576
693
|
read: partitions?.read ?? [],
|
|
577
694
|
edit: partitions?.edit ?? [],
|
|
@@ -580,22 +697,23 @@ function manifest(partitions) {
|
|
|
580
697
|
};
|
|
581
698
|
}
|
|
582
699
|
/**
|
|
583
|
-
*
|
|
700
|
+
* Assembles an `Outcome` from a rank and its result text.
|
|
584
701
|
*
|
|
585
702
|
* @param rank - The one-based rank; lower ranks matter more.
|
|
586
703
|
* @param text - The result, never a step.
|
|
587
|
-
* @param required -
|
|
704
|
+
* @param required - If `true`, the outcome gates "done"; if `false`, it is desirable but not
|
|
705
|
+
* blocking. Default: `true`.
|
|
588
706
|
* @returns A fresh `Outcome`.
|
|
589
707
|
*
|
|
590
708
|
* @example
|
|
591
709
|
* ```ts
|
|
592
|
-
* import {
|
|
710
|
+
* import { buildOutcome } from '@orkestrel/brief'
|
|
593
711
|
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
712
|
+
* buildOutcome(1, 'useForm uses native FormData with no behavior change') // required: true
|
|
713
|
+
* buildOutcome(2, 'the diff stays under 200 lines', false)
|
|
596
714
|
* ```
|
|
597
715
|
*/
|
|
598
|
-
function
|
|
716
|
+
function buildOutcome(rank, text, required = true) {
|
|
599
717
|
return {
|
|
600
718
|
rank,
|
|
601
719
|
text,
|
|
@@ -603,7 +721,7 @@ function outcome(rank, text, required = true) {
|
|
|
603
721
|
};
|
|
604
722
|
}
|
|
605
723
|
/**
|
|
606
|
-
*
|
|
724
|
+
* Assembles a `Given` from a category, a name, and a value.
|
|
607
725
|
*
|
|
608
726
|
* @param category - The kind of fact — a convention, a version, a constraint.
|
|
609
727
|
* @param name - The fact's name.
|
|
@@ -612,12 +730,12 @@ function outcome(rank, text, required = true) {
|
|
|
612
730
|
*
|
|
613
731
|
* @example
|
|
614
732
|
* ```ts
|
|
615
|
-
* import {
|
|
733
|
+
* import { buildGiven } from '@orkestrel/brief'
|
|
616
734
|
*
|
|
617
|
-
*
|
|
735
|
+
* buildGiven('convention', 'indentation', 'tabs')
|
|
618
736
|
* ```
|
|
619
737
|
*/
|
|
620
|
-
function
|
|
738
|
+
function buildGiven(category, name, value) {
|
|
621
739
|
return {
|
|
622
740
|
category,
|
|
623
741
|
name,
|
|
@@ -625,32 +743,32 @@ function given(category, name, value) {
|
|
|
625
743
|
};
|
|
626
744
|
}
|
|
627
745
|
/**
|
|
628
|
-
*
|
|
746
|
+
* Assembles an `Example` from an exemplar input and its expected output.
|
|
629
747
|
*
|
|
630
748
|
* @param input - The exemplar input.
|
|
631
|
-
* @param
|
|
749
|
+
* @param output - The expected output for that input.
|
|
632
750
|
* @param note - Optional detail; the key is OMITTED when absent.
|
|
633
751
|
* @returns A fresh `Example`.
|
|
634
752
|
*
|
|
635
753
|
* @example
|
|
636
754
|
* ```ts
|
|
637
|
-
* import {
|
|
755
|
+
* import { buildExample } from '@orkestrel/brief'
|
|
638
756
|
*
|
|
639
|
-
*
|
|
757
|
+
* buildExample('<input required>', 'validity read from el.validity')
|
|
640
758
|
* ```
|
|
641
759
|
*/
|
|
642
|
-
function
|
|
760
|
+
function buildExample(input, output, note) {
|
|
643
761
|
return note === void 0 ? {
|
|
644
762
|
input,
|
|
645
|
-
output
|
|
763
|
+
output
|
|
646
764
|
} : {
|
|
647
765
|
input,
|
|
648
|
-
output
|
|
766
|
+
output,
|
|
649
767
|
note
|
|
650
768
|
};
|
|
651
769
|
}
|
|
652
770
|
/**
|
|
653
|
-
*
|
|
771
|
+
* Assembles a `Citation` from a name, a URL, and the note that justifies citing it.
|
|
654
772
|
*
|
|
655
773
|
* @param name - The source's display name.
|
|
656
774
|
* @param url - Where the source lives.
|
|
@@ -659,16 +777,16 @@ function example(input, result, note) {
|
|
|
659
777
|
*
|
|
660
778
|
* @example
|
|
661
779
|
* ```ts
|
|
662
|
-
* import {
|
|
780
|
+
* import { buildCitation } from '@orkestrel/brief'
|
|
663
781
|
*
|
|
664
|
-
*
|
|
782
|
+
* buildCitation(
|
|
665
783
|
* 'MDN Constraint Validation',
|
|
666
784
|
* 'https://developer.mozilla.org/',
|
|
667
785
|
* 'the native validity behavior being adopted',
|
|
668
786
|
* )
|
|
669
787
|
* ```
|
|
670
788
|
*/
|
|
671
|
-
function
|
|
789
|
+
function buildCitation(name, url, note) {
|
|
672
790
|
return {
|
|
673
791
|
name,
|
|
674
792
|
url,
|
|
@@ -676,23 +794,23 @@ function citation(name, url, note) {
|
|
|
676
794
|
};
|
|
677
795
|
}
|
|
678
796
|
/**
|
|
679
|
-
*
|
|
797
|
+
* Assembles a `Gap` from the section it belongs to and the question that would close it.
|
|
680
798
|
*
|
|
681
799
|
* @param field - The brief section the unknown belongs to.
|
|
682
800
|
* @param question - The question that would close it.
|
|
683
|
-
* @param overrides - Optional `blocking`
|
|
684
|
-
*
|
|
801
|
+
* @param overrides - Optional `blocking` and `candidates`; an absent `candidates` key is
|
|
802
|
+
* OMITTED entirely. Default: `blocking: false`.
|
|
685
803
|
* @returns A fresh `Gap`.
|
|
686
804
|
*
|
|
687
805
|
* @example
|
|
688
806
|
* ```ts
|
|
689
|
-
* import {
|
|
807
|
+
* import { buildGap } from '@orkestrel/brief'
|
|
690
808
|
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
809
|
+
* buildGap('rules', 'Does validation message wording need to change?') // blocking: false
|
|
810
|
+
* buildGap('output', 'Diff or full files?', { blocking: true, candidates: ['diff', 'code'] })
|
|
693
811
|
* ```
|
|
694
812
|
*/
|
|
695
|
-
function
|
|
813
|
+
function buildGap(field, question, overrides) {
|
|
696
814
|
const blocking = overrides?.blocking ?? false;
|
|
697
815
|
return overrides?.candidates === void 0 ? {
|
|
698
816
|
field,
|
|
@@ -706,7 +824,7 @@ function gap(field, question, overrides) {
|
|
|
706
824
|
};
|
|
707
825
|
}
|
|
708
826
|
/**
|
|
709
|
-
*
|
|
827
|
+
* Assembles a `Risk` from a severity, what could go wrong, and the mitigation that answers it.
|
|
710
828
|
*
|
|
711
829
|
* @param severity - The closed severity.
|
|
712
830
|
* @param text - What could go wrong.
|
|
@@ -715,12 +833,12 @@ function gap(field, question, overrides) {
|
|
|
715
833
|
*
|
|
716
834
|
* @example
|
|
717
835
|
* ```ts
|
|
718
|
-
* import {
|
|
836
|
+
* import { buildRisk } from '@orkestrel/brief'
|
|
719
837
|
*
|
|
720
|
-
*
|
|
838
|
+
* buildRisk('medium', 'native validation differs subtly', 'assert message and state in tests')
|
|
721
839
|
* ```
|
|
722
840
|
*/
|
|
723
|
-
function
|
|
841
|
+
function buildRisk(severity, text, mitigation) {
|
|
724
842
|
return {
|
|
725
843
|
severity,
|
|
726
844
|
text,
|
|
@@ -728,7 +846,7 @@ function risk(severity, text, mitigation) {
|
|
|
728
846
|
};
|
|
729
847
|
}
|
|
730
848
|
/**
|
|
731
|
-
*
|
|
849
|
+
* Assembles an `Output` from a format plus its optional refinements.
|
|
732
850
|
*
|
|
733
851
|
* @param format - The closed deliverable format.
|
|
734
852
|
* @param overrides - Optional `sections` / `include` / `exclude`; absent keys are OMITTED.
|
|
@@ -736,13 +854,13 @@ function risk(severity, text, mitigation) {
|
|
|
736
854
|
*
|
|
737
855
|
* @example
|
|
738
856
|
* ```ts
|
|
739
|
-
* import {
|
|
857
|
+
* import { buildOutput } from '@orkestrel/brief'
|
|
740
858
|
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
859
|
+
* buildOutput('markdown') // { format: 'markdown' }
|
|
860
|
+
* buildOutput('diff', { include: ['updated useForm.ts'] })
|
|
743
861
|
* ```
|
|
744
862
|
*/
|
|
745
|
-
function
|
|
863
|
+
function buildOutput(format, overrides) {
|
|
746
864
|
return {
|
|
747
865
|
format,
|
|
748
866
|
...overrides?.sections === void 0 ? {} : { sections: overrides.sections },
|
|
@@ -751,7 +869,7 @@ function output(format, overrides) {
|
|
|
751
869
|
};
|
|
752
870
|
}
|
|
753
871
|
/**
|
|
754
|
-
*
|
|
872
|
+
* Assembles a `Proof` from what the check settles and the command that settles it.
|
|
755
873
|
*
|
|
756
874
|
* @param text - What the check settles.
|
|
757
875
|
* @param command - The command whose exit signal settles it.
|
|
@@ -759,41 +877,41 @@ function output(format, overrides) {
|
|
|
759
877
|
*
|
|
760
878
|
* @example
|
|
761
879
|
* ```ts
|
|
762
|
-
* import {
|
|
880
|
+
* import { buildProof } from '@orkestrel/brief'
|
|
763
881
|
*
|
|
764
|
-
*
|
|
882
|
+
* buildProof('type-check and lint pass', 'npm run check')
|
|
765
883
|
* ```
|
|
766
884
|
*/
|
|
767
|
-
function
|
|
885
|
+
function buildProof(text, command) {
|
|
768
886
|
return {
|
|
769
887
|
text,
|
|
770
888
|
command
|
|
771
889
|
};
|
|
772
890
|
}
|
|
773
891
|
/**
|
|
774
|
-
*
|
|
892
|
+
* Assembles a `Brief` from a `Task` plus section overrides.
|
|
775
893
|
*
|
|
776
894
|
* @param subject - The task the brief is about.
|
|
777
|
-
* @param overrides - Any sections to fill;
|
|
778
|
-
* `
|
|
779
|
-
* `
|
|
895
|
+
* @param overrides - Any sections to fill; `trace` / `hash` stay OMITTED so `pinBrief` can
|
|
896
|
+
* fill them. Default: `[]` for every absent collection and `buildOutput('markdown')` for
|
|
897
|
+
* `output`.
|
|
780
898
|
* @returns A fresh, unpinned `Brief`.
|
|
781
899
|
*
|
|
782
900
|
* @example
|
|
783
901
|
* ```ts
|
|
784
|
-
* import {
|
|
902
|
+
* import { buildBrief, buildOutcome, buildProof, buildTask } from '@orkestrel/brief'
|
|
785
903
|
*
|
|
786
|
-
*
|
|
787
|
-
* outcomes: [
|
|
788
|
-
* proofs: [
|
|
904
|
+
* buildBrief(buildTask('audit', 'code', 'Audit the barrel for undocumented exports.'), {
|
|
905
|
+
* outcomes: [buildOutcome(1, 'every export appears in the guide')],
|
|
906
|
+
* proofs: [buildProof('parity passes', 'npm run test:guides')],
|
|
789
907
|
* })
|
|
790
908
|
* ```
|
|
791
909
|
*/
|
|
792
|
-
function
|
|
910
|
+
function buildBrief(subject, overrides) {
|
|
793
911
|
return {
|
|
794
912
|
task: subject,
|
|
795
913
|
authority: overrides?.authority ?? [],
|
|
796
|
-
manifest: overrides?.manifest ??
|
|
914
|
+
manifest: overrides?.manifest ?? buildManifest(),
|
|
797
915
|
outcomes: overrides?.outcomes ?? [],
|
|
798
916
|
rules: overrides?.rules ?? [],
|
|
799
917
|
invariants: overrides?.invariants ?? [],
|
|
@@ -803,17 +921,17 @@ function brief(subject, overrides) {
|
|
|
803
921
|
citations: overrides?.citations ?? [],
|
|
804
922
|
gaps: overrides?.gaps ?? [],
|
|
805
923
|
risks: overrides?.risks ?? [],
|
|
806
|
-
output: overrides?.output ??
|
|
924
|
+
output: overrides?.output ?? buildOutput("markdown"),
|
|
807
925
|
proofs: overrides?.proofs ?? []
|
|
808
926
|
};
|
|
809
927
|
}
|
|
810
928
|
/**
|
|
811
|
-
*
|
|
929
|
+
* Assembles the fail-closed readiness gate as a reasons `LogicalDefinition`.
|
|
812
930
|
*
|
|
813
931
|
* @remarks
|
|
814
|
-
*
|
|
815
|
-
*
|
|
816
|
-
*
|
|
932
|
+
* Each readiness rule derives one named fact from `briefToSubject`'s measures, and a final
|
|
933
|
+
* `ready` rule conjoins them all. Forward chaining reports the LAST rule's conclusion, so
|
|
934
|
+
* `LogicalResult.conclusion` is exactly `ready`.
|
|
817
935
|
*
|
|
818
936
|
* The gate takes NO parameters, and that is deliberate rather than unfinished. The
|
|
819
937
|
* reasoner overlays every derived fact into one flat namespace, so a caller rule named
|
|
@@ -827,50 +945,50 @@ function brief(subject, overrides) {
|
|
|
827
945
|
*
|
|
828
946
|
* @example
|
|
829
947
|
* ```ts
|
|
830
|
-
* import { briefToSubject,
|
|
948
|
+
* import { briefToSubject, buildGateDefinition } from '@orkestrel/brief'
|
|
831
949
|
* import { createLogicalReasoner, createReason } from '@orkestrel/reason'
|
|
832
950
|
*
|
|
833
951
|
* const reason = createReason({ reasoners: [createLogicalReasoner()] })
|
|
834
|
-
* const verdict = reason.reason(briefToSubject(pinned),
|
|
952
|
+
* const verdict = reason.reason(briefToSubject(pinned), buildGateDefinition())
|
|
835
953
|
* reason.destroy()
|
|
836
954
|
* ```
|
|
837
955
|
*/
|
|
838
|
-
function
|
|
956
|
+
function buildGateDefinition() {
|
|
839
957
|
const readiness = [
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
958
|
+
createRule("specified", [createAtom("blocking", "equals", 0)], createAtom("specified", "equals", true)),
|
|
959
|
+
createRule("aimed", [createCompound("and", [createAtom("outcomes", "above", 0), createAtom("required", "above", 0)])], createAtom("aimed", "equals", true)),
|
|
960
|
+
createRule("proven", [createAtom("proofs", "above", 0)], createAtom("proven", "equals", true)),
|
|
961
|
+
createRule("disjoint", [createAtom("overlaps", "equals", 0)], createAtom("disjoint", "equals", true)),
|
|
962
|
+
createRule("granted", [createAtom("ungranted", "equals", 0)], createAtom("granted", "equals", true)),
|
|
963
|
+
createRule("single", [createAtom("sentences", "equals", 1)], createAtom("single", "equals", true))
|
|
846
964
|
];
|
|
847
|
-
return
|
|
965
|
+
return createLogicalDefinition(GATE_ID, "Brief readiness", [...readiness, createRule("ready", [createCompound("and", readiness.map((entry) => createAtom(entry.id, "equals", true)))], createAtom("ready", "equals", true))]);
|
|
848
966
|
}
|
|
849
967
|
/**
|
|
850
|
-
*
|
|
968
|
+
* Lists the readiness rules a brief fails, computed directly from its own measures.
|
|
851
969
|
*
|
|
852
970
|
* @remarks
|
|
853
|
-
* The gate's decision, in code. `
|
|
971
|
+
* The gate's decision, in code. `buildGateDefinition()` states the same rules as data for a
|
|
854
972
|
* reasoner to narrate, and a narration is not a decision: `BriefCompilerOptions.reason` lets a
|
|
855
973
|
* caller supply the engine, and an engine that answers "met" to everything would otherwise
|
|
856
974
|
* emit a brief with no proofs. `compile` refuses on THIS and keeps the verdict for its
|
|
857
975
|
* trace, so a supplied engine can add detail and never remove a refusal.
|
|
858
976
|
*
|
|
859
|
-
* The
|
|
860
|
-
* is what stops
|
|
977
|
+
* The data and the code must agree. `tests/src/core/helpers.test.ts` drives both over one
|
|
978
|
+
* value set, which is what stops them from drifting apart.
|
|
861
979
|
*
|
|
862
980
|
* @param source - The brief to measure.
|
|
863
981
|
* @returns The unmet rule ids, in gate order; empty when the brief is ready.
|
|
864
982
|
*
|
|
865
983
|
* @example
|
|
866
984
|
* ```ts
|
|
867
|
-
* import {
|
|
985
|
+
* import { buildBrief, buildOutcome, buildProof, buildTask, findUnmetRules } from '@orkestrel/brief'
|
|
868
986
|
*
|
|
869
|
-
* findUnmetRules(
|
|
987
|
+
* findUnmetRules(buildBrief(buildTask('plan', 'ops', 'Plan the release.'))) // ['aimed', 'proven']
|
|
870
988
|
* findUnmetRules(
|
|
871
|
-
*
|
|
872
|
-
* outcomes: [
|
|
873
|
-
* proofs: [
|
|
989
|
+
* buildBrief(buildTask('plan', 'ops', 'Plan the release.'), {
|
|
990
|
+
* outcomes: [buildOutcome(1, 'shipped')],
|
|
991
|
+
* proofs: [buildProof('x', 'npm test')],
|
|
874
992
|
* }),
|
|
875
993
|
* ) // []
|
|
876
994
|
* ```
|
|
@@ -886,7 +1004,7 @@ function findUnmetRules(source) {
|
|
|
886
1004
|
return unready;
|
|
887
1005
|
}
|
|
888
1006
|
/**
|
|
889
|
-
*
|
|
1007
|
+
* Counts the sentences a statement holds.
|
|
890
1008
|
*
|
|
891
1009
|
* @remarks
|
|
892
1010
|
* A terminator run (`.`, `!`, `?`) followed by whitespace or the end of the text closes one
|
|
@@ -924,17 +1042,21 @@ function countSentences(statement) {
|
|
|
924
1042
|
return /[.!?]$/u.test(text) ? matches.length : matches.length + 1;
|
|
925
1043
|
}
|
|
926
1044
|
/**
|
|
927
|
-
*
|
|
1045
|
+
* Lists the gaps that block emission.
|
|
1046
|
+
*
|
|
1047
|
+
* @remarks
|
|
1048
|
+
* A non-empty result means the gate must fail closed: a blocking gap has no safe default, so
|
|
1049
|
+
* the compile yields a visible incomplete `Briefing` carrying the questions instead of a brief.
|
|
928
1050
|
*
|
|
929
1051
|
* @param source - The brief to inspect.
|
|
930
1052
|
* @returns Every gap carrying `blocking: true`, in declaration order.
|
|
931
1053
|
*
|
|
932
1054
|
* @example
|
|
933
1055
|
* ```ts
|
|
934
|
-
* import {
|
|
1056
|
+
* import { buildBrief, buildGap, buildTask, findBlockingGaps } from '@orkestrel/brief'
|
|
935
1057
|
*
|
|
936
|
-
* const draft =
|
|
937
|
-
* gaps: [
|
|
1058
|
+
* const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'), {
|
|
1059
|
+
* gaps: [buildGap('output', 'Diff or files?', { blocking: true })],
|
|
938
1060
|
* })
|
|
939
1061
|
* findBlockingGaps(draft).length // 1
|
|
940
1062
|
* ```
|
|
@@ -943,18 +1065,18 @@ function findBlockingGaps(source) {
|
|
|
943
1065
|
return source.gaps.filter((entry) => entry.blocking);
|
|
944
1066
|
}
|
|
945
1067
|
/**
|
|
946
|
-
*
|
|
1068
|
+
* Lists the authority paths the manifest never grants access to.
|
|
947
1069
|
*
|
|
948
1070
|
* @remarks
|
|
949
1071
|
* An authority the executor cannot open is an instruction it cannot follow, so every ranked
|
|
950
|
-
* path must appear in `read`, `edit`, or `locked`. Those
|
|
1072
|
+
* path must appear in `read`, `edit`, or `locked`. Those are the grants: `locked` is a
|
|
951
1073
|
* grant, because read-only is exactly what obeying a file requires.
|
|
952
1074
|
*
|
|
953
|
-
* This subsumes the narrower question of an authority sitting in `forbidden`. The
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
*
|
|
957
|
-
*
|
|
1075
|
+
* This subsumes the narrower question of an authority sitting in `forbidden`. The partitions
|
|
1076
|
+
* are disjoint — `findManifestOverlaps` and the `disjoint` rule enforce it — so a forbidden
|
|
1077
|
+
* path is in none of the grants and is reported here. An authority named in NO partition at
|
|
1078
|
+
* all is reported for the same reason, and that is the case a forbidden-only check misses
|
|
1079
|
+
* entirely: the brief never says the executor may open what it must obey.
|
|
958
1080
|
*
|
|
959
1081
|
* Paths are compared as EXACT strings, matching `findManifestOverlaps`. A glob is never
|
|
960
1082
|
* expanded, so `read: 'guides/**'` does not grant `authority: 'guides/brief.md'`. State a
|
|
@@ -965,11 +1087,17 @@ function findBlockingGaps(source) {
|
|
|
965
1087
|
*
|
|
966
1088
|
* @example
|
|
967
1089
|
* ```ts
|
|
968
|
-
* import {
|
|
969
|
-
*
|
|
970
|
-
*
|
|
971
|
-
*
|
|
972
|
-
*
|
|
1090
|
+
* import {
|
|
1091
|
+
* buildBrief,
|
|
1092
|
+
* buildManifest,
|
|
1093
|
+
* buildReference,
|
|
1094
|
+
* buildTask,
|
|
1095
|
+
* findUngrantedAuthority,
|
|
1096
|
+
* } from '@orkestrel/brief'
|
|
1097
|
+
*
|
|
1098
|
+
* const draft = buildBrief(buildTask('debug', 'code', 'Fix the leak.'), {
|
|
1099
|
+
* authority: [buildReference('AGENTS.md', 'project law')],
|
|
1100
|
+
* manifest: buildManifest(),
|
|
973
1101
|
* })
|
|
974
1102
|
* findUngrantedAuthority(draft) // ['AGENTS.md'] — ranked, but no partition opens it
|
|
975
1103
|
* ```
|
|
@@ -985,10 +1113,10 @@ function findUngrantedAuthority(source) {
|
|
|
985
1113
|
return ungranted;
|
|
986
1114
|
}
|
|
987
1115
|
/**
|
|
988
|
-
*
|
|
1116
|
+
* Lists the paths appearing in more than one manifest partition.
|
|
989
1117
|
*
|
|
990
1118
|
* @remarks
|
|
991
|
-
* Duplicates WITHIN one partition are not an overlap; the
|
|
1119
|
+
* Duplicates WITHIN one partition are not an overlap; the partitions must be
|
|
992
1120
|
* mutually disjoint, which is what `validateBrief` errors on.
|
|
993
1121
|
*
|
|
994
1122
|
* Paths are compared as EXACT strings. A glob is never expanded, so `edit: 'app/file.ts'`
|
|
@@ -1000,12 +1128,18 @@ function findUngrantedAuthority(source) {
|
|
|
1000
1128
|
*
|
|
1001
1129
|
* @example
|
|
1002
1130
|
* ```ts
|
|
1003
|
-
* import {
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1131
|
+
* import {
|
|
1132
|
+
* buildBrief,
|
|
1133
|
+
* buildManifest,
|
|
1134
|
+
* buildReference,
|
|
1135
|
+
* buildTask,
|
|
1136
|
+
* findManifestOverlaps,
|
|
1137
|
+
* } from '@orkestrel/brief'
|
|
1138
|
+
*
|
|
1139
|
+
* const draft = buildBrief(buildTask('debug', 'code', 'Fix the leak.'), {
|
|
1140
|
+
* manifest: buildManifest({
|
|
1141
|
+
* edit: [buildReference('src/core/BriefCompiler.ts', 'the leaking pipeline')],
|
|
1142
|
+
* locked: [buildReference('src/core/BriefCompiler.ts', 'the published contract')],
|
|
1009
1143
|
* }),
|
|
1010
1144
|
* })
|
|
1011
1145
|
* findManifestOverlaps(draft) // ['src/core/BriefCompiler.ts']
|
|
@@ -1025,7 +1159,7 @@ function findManifestOverlaps(source) {
|
|
|
1025
1159
|
return overlaps;
|
|
1026
1160
|
}
|
|
1027
1161
|
/**
|
|
1028
|
-
*
|
|
1162
|
+
* Lists the open gaps with no assumption to stand on.
|
|
1029
1163
|
*
|
|
1030
1164
|
* @remarks
|
|
1031
1165
|
* The discipline is exactly one recorded assumption per open gap, so the open gaps past
|
|
@@ -1037,10 +1171,10 @@ function findManifestOverlaps(source) {
|
|
|
1037
1171
|
*
|
|
1038
1172
|
* @example
|
|
1039
1173
|
* ```ts
|
|
1040
|
-
* import {
|
|
1174
|
+
* import { buildBrief, buildGap, buildTask, findUnpairedGaps } from '@orkestrel/brief'
|
|
1041
1175
|
*
|
|
1042
|
-
* const draft =
|
|
1043
|
-
* gaps: [
|
|
1176
|
+
* const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'), {
|
|
1177
|
+
* gaps: [buildGap('rules', 'Keep the wording?'), buildGap('output', 'Diff or files?')],
|
|
1044
1178
|
* assumptions: ['Wording is preserved.'],
|
|
1045
1179
|
* })
|
|
1046
1180
|
* findUnpairedGaps(draft).length // 1
|
|
@@ -1050,16 +1184,16 @@ function findUnpairedGaps(source) {
|
|
|
1050
1184
|
return source.gaps.filter((entry) => !entry.blocking).slice(source.assumptions.length);
|
|
1051
1185
|
}
|
|
1052
1186
|
/**
|
|
1053
|
-
*
|
|
1187
|
+
* Projects a brief into the reasons `Subject` of readiness measures the gate reads.
|
|
1054
1188
|
*
|
|
1055
1189
|
* @param source - The brief to measure.
|
|
1056
|
-
* @returns A flat record of counts plus the task's
|
|
1190
|
+
* @returns A flat record of counts plus the task's vocabulary values.
|
|
1057
1191
|
*
|
|
1058
1192
|
* @example
|
|
1059
1193
|
* ```ts
|
|
1060
|
-
* import {
|
|
1194
|
+
* import { briefToSubject, buildBrief, buildProof, buildTask } from '@orkestrel/brief'
|
|
1061
1195
|
*
|
|
1062
|
-
* briefToSubject(
|
|
1196
|
+
* briefToSubject(buildBrief(buildTask('test', 'code', 'Cover the gate.'), { proofs: [buildProof('x', 'y')] }))
|
|
1063
1197
|
* // { operation: 'test', domain: 'code', sentences: 1, proofs: 1, … }
|
|
1064
1198
|
* ```
|
|
1065
1199
|
*/
|
|
@@ -1086,7 +1220,7 @@ function briefToSubject(source) {
|
|
|
1086
1220
|
};
|
|
1087
1221
|
}
|
|
1088
1222
|
/**
|
|
1089
|
-
*
|
|
1223
|
+
* Runs the semantic pass over an already-shape-valid brief.
|
|
1090
1224
|
*
|
|
1091
1225
|
* @remarks
|
|
1092
1226
|
* ERRORS are the structural violations no assumption can paper over: a manifest
|
|
@@ -1100,11 +1234,11 @@ function briefToSubject(source) {
|
|
|
1100
1234
|
*
|
|
1101
1235
|
* @example
|
|
1102
1236
|
* ```ts
|
|
1103
|
-
* import {
|
|
1237
|
+
* import { buildBrief, buildProof, buildTask, validateBrief } from '@orkestrel/brief'
|
|
1104
1238
|
*
|
|
1105
|
-
* validateBrief(
|
|
1239
|
+
* validateBrief(buildBrief(buildTask('plan', 'ops', 'Plan the release.'))) // valid: false — no proofs
|
|
1106
1240
|
* validateBrief(
|
|
1107
|
-
*
|
|
1241
|
+
* buildBrief(buildTask('plan', 'ops', 'Plan the release.'), { proofs: [buildProof('ok', 'npm test')] }),
|
|
1108
1242
|
* ) // valid: true
|
|
1109
1243
|
* ```
|
|
1110
1244
|
*/
|
|
@@ -1132,7 +1266,7 @@ function validateBrief(source) {
|
|
|
1132
1266
|
};
|
|
1133
1267
|
}
|
|
1134
1268
|
/**
|
|
1135
|
-
*
|
|
1269
|
+
* Computes the canonical structural digest of a brief's content.
|
|
1136
1270
|
*
|
|
1137
1271
|
* @remarks
|
|
1138
1272
|
* `trace` and `hash` are stripped before digesting, so the value is the identity of what
|
|
@@ -1144,9 +1278,9 @@ function validateBrief(source) {
|
|
|
1144
1278
|
*
|
|
1145
1279
|
* @example
|
|
1146
1280
|
* ```ts
|
|
1147
|
-
* import {
|
|
1281
|
+
* import { briefToHash, buildBrief, buildTask, pinBrief } from '@orkestrel/brief'
|
|
1148
1282
|
*
|
|
1149
|
-
* const draft =
|
|
1283
|
+
* const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'))
|
|
1150
1284
|
* briefToHash(draft) === briefToHash(pinBrief(draft)) // true — pinning does not move it
|
|
1151
1285
|
* ```
|
|
1152
1286
|
*/
|
|
@@ -1154,7 +1288,7 @@ function briefToHash(source) {
|
|
|
1154
1288
|
return digestValue(briefToContent(source));
|
|
1155
1289
|
}
|
|
1156
1290
|
/**
|
|
1157
|
-
*
|
|
1291
|
+
* Renders the canonical text of exactly what a brief's hash describes.
|
|
1158
1292
|
*
|
|
1159
1293
|
* @remarks
|
|
1160
1294
|
* `trace` and `hash` are stripped, then interprets `canonicalize` renders the rest in a
|
|
@@ -1166,9 +1300,9 @@ function briefToHash(source) {
|
|
|
1166
1300
|
*
|
|
1167
1301
|
* @example
|
|
1168
1302
|
* ```ts
|
|
1169
|
-
* import {
|
|
1303
|
+
* import { briefToContent, buildBrief, buildTask, pinBrief } from '@orkestrel/brief'
|
|
1170
1304
|
*
|
|
1171
|
-
* const draft =
|
|
1305
|
+
* const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'))
|
|
1172
1306
|
* briefToContent(draft) === briefToContent(pinBrief(draft)) // true — pinning adds no content
|
|
1173
1307
|
* ```
|
|
1174
1308
|
*/
|
|
@@ -1177,7 +1311,7 @@ function briefToContent(source) {
|
|
|
1177
1311
|
return canonicalize(content);
|
|
1178
1312
|
}
|
|
1179
1313
|
/**
|
|
1180
|
-
*
|
|
1314
|
+
* Freezes a value and everything reachable from it.
|
|
1181
1315
|
*
|
|
1182
1316
|
* @remarks
|
|
1183
1317
|
* `Object.freeze` is SHALLOW, so freezing a record leaves every nested array and object
|
|
@@ -1191,7 +1325,7 @@ function briefToContent(source) {
|
|
|
1191
1325
|
* Reaches PLAIN objects and arrays, which is the whole of a `Brief` — it is JSON-serializable
|
|
1192
1326
|
* by contract. A `Map`, `Set`, or typed array is frozen as an object and its CONTENTS are left
|
|
1193
1327
|
* writable, and `Object.isFrozen` reports `true` for it either way. Nothing this package
|
|
1194
|
-
* produces contains one; a caller freezing their own value
|
|
1328
|
+
* produces contains one; the limit lands on a caller freezing their own value.
|
|
1195
1329
|
*
|
|
1196
1330
|
* @param value - The value to freeze in place; returned for convenience.
|
|
1197
1331
|
* @returns The same value, now deeply frozen.
|
|
@@ -1208,7 +1342,7 @@ function freezeDeep(value) {
|
|
|
1208
1342
|
return freezeBranch(value, /* @__PURE__ */ new WeakSet());
|
|
1209
1343
|
}
|
|
1210
1344
|
/**
|
|
1211
|
-
*
|
|
1345
|
+
* Freezes one branch of a value graph, skipping what the visited set already holds.
|
|
1212
1346
|
*
|
|
1213
1347
|
* @param value - The branch to freeze.
|
|
1214
1348
|
* @param seen - The objects already frozen on this walk; what makes a cycle terminate.
|
|
@@ -1230,7 +1364,7 @@ function freezeBranch(value, seen) {
|
|
|
1230
1364
|
return value;
|
|
1231
1365
|
}
|
|
1232
1366
|
/**
|
|
1233
|
-
*
|
|
1367
|
+
* Renders a value thrown by a stage into a message.
|
|
1234
1368
|
*
|
|
1235
1369
|
* @remarks
|
|
1236
1370
|
* TOTAL: it never throws, for any input. That is load-bearing rather than tidy, because this
|
|
@@ -1239,7 +1373,7 @@ function freezeBranch(value, seen) {
|
|
|
1239
1373
|
* falsifies the package's central promise that a failing stage yields an incomplete
|
|
1240
1374
|
* `Briefing` rather than an exception.
|
|
1241
1375
|
*
|
|
1242
|
-
*
|
|
1376
|
+
* Real inputs used to throw: an `Error` subclass whose `message` getter throws, a value
|
|
1243
1377
|
* whose string conversion throws, and a null-prototype object, which has no inherited
|
|
1244
1378
|
* conversion for String() to reach. Each is wrapped, and an unreadable value degrades to its
|
|
1245
1379
|
* type rather than propagating.
|
|
@@ -1263,10 +1397,10 @@ function errorToMessage(error) {
|
|
|
1263
1397
|
return `an unreadable ${typeof error} was thrown`;
|
|
1264
1398
|
}
|
|
1265
1399
|
/**
|
|
1266
|
-
*
|
|
1400
|
+
* Narrows unknown data to a `Brief`, throwing when it is off-contract.
|
|
1267
1401
|
*
|
|
1268
1402
|
* @remarks
|
|
1269
|
-
* The throwing half of the intake pair: this returns its argument by IDENTITY
|
|
1403
|
+
* The throwing half of the intake pair: this returns its argument by IDENTITY after the
|
|
1270
1404
|
* guard passes, while `parseBrief` returns `undefined` for bad input. It constructs
|
|
1271
1405
|
* nothing, so it is an assertion rather than a factory. Reserve it for programmer-error
|
|
1272
1406
|
* contexts where invalidity is a bug.
|
|
@@ -1280,24 +1414,24 @@ function errorToMessage(error) {
|
|
|
1280
1414
|
* `briefToTrace` read the value they are handed instead, so a caller reaching one of those
|
|
1281
1415
|
* directly owns that reading. Pass `assertBrief` a value you already own.
|
|
1282
1416
|
*
|
|
1283
|
-
* @param
|
|
1417
|
+
* @param value - The candidate brief value.
|
|
1284
1418
|
* @returns The same value, now known to satisfy {@link Brief}.
|
|
1285
|
-
* @throws {@link BriefError} `INVALID` when `
|
|
1419
|
+
* @throws {@link BriefError} `INVALID` when `value` fails `isBrief`.
|
|
1286
1420
|
*
|
|
1287
1421
|
* @example
|
|
1288
1422
|
* ```ts
|
|
1289
|
-
* import { assertBrief,
|
|
1423
|
+
* import { assertBrief, buildBrief, buildProof, buildTask } from '@orkestrel/brief'
|
|
1290
1424
|
*
|
|
1291
|
-
* assertBrief(
|
|
1425
|
+
* assertBrief(buildBrief(buildTask('plan', 'ops', 'Plan the release.'), { proofs: [buildProof('x', 'y')] }))
|
|
1292
1426
|
* assertBrief({ task: { operation: 'plan', domain: 'ops', statement: 'x.' } }) // throws INVALID
|
|
1293
1427
|
* ```
|
|
1294
1428
|
*/
|
|
1295
|
-
function assertBrief(
|
|
1296
|
-
if (!isBrief(
|
|
1297
|
-
return
|
|
1429
|
+
function assertBrief(value) {
|
|
1430
|
+
if (!isBrief(value)) throw new BriefError("INVALID", "Brief failed the exact-record contract", { field: "brief" });
|
|
1431
|
+
return value;
|
|
1298
1432
|
}
|
|
1299
1433
|
/**
|
|
1300
|
-
*
|
|
1434
|
+
* Returns a fresh brief with `trace` and `hash` derived from its own content.
|
|
1301
1435
|
*
|
|
1302
1436
|
* @remarks
|
|
1303
1437
|
* Deterministic: no clock, no randomness, no run-specific data. Any existing `trace` /
|
|
@@ -1313,9 +1447,9 @@ function assertBrief(data) {
|
|
|
1313
1447
|
*
|
|
1314
1448
|
* @example
|
|
1315
1449
|
* ```ts
|
|
1316
|
-
* import {
|
|
1450
|
+
* import { buildBrief, buildTask, pinBrief } from '@orkestrel/brief'
|
|
1317
1451
|
*
|
|
1318
|
-
* const pinned = pinBrief(
|
|
1452
|
+
* const pinned = pinBrief(buildBrief(buildTask('document', 'writing', 'Write the brief guide.')))
|
|
1319
1453
|
* pinned.hash // an 8-hex-digit structural digest
|
|
1320
1454
|
* pinned.trace // 'document/writing · outcomes:0 · gaps:0/0 · proofs:0'
|
|
1321
1455
|
* ```
|
|
@@ -1330,7 +1464,7 @@ function pinBrief(source) {
|
|
|
1330
1464
|
});
|
|
1331
1465
|
}
|
|
1332
1466
|
/**
|
|
1333
|
-
*
|
|
1467
|
+
* Renders the one-line census `pinBrief` stamps onto a brief.
|
|
1334
1468
|
*
|
|
1335
1469
|
* @remarks
|
|
1336
1470
|
* Extracted so it has ONE implementation. `pinBrief` derives it and `BriefManager` re-derives
|
|
@@ -1343,9 +1477,9 @@ function pinBrief(source) {
|
|
|
1343
1477
|
*
|
|
1344
1478
|
* @example
|
|
1345
1479
|
* ```ts
|
|
1346
|
-
* import {
|
|
1480
|
+
* import { briefToTrace, buildBrief, buildTask } from '@orkestrel/brief'
|
|
1347
1481
|
*
|
|
1348
|
-
* briefToTrace(
|
|
1482
|
+
* briefToTrace(buildBrief(buildTask('document', 'writing', 'Write the guide.')))
|
|
1349
1483
|
* // 'document/writing · outcomes:0 · gaps:0/0 · proofs:0'
|
|
1350
1484
|
* ```
|
|
1351
1485
|
*/
|
|
@@ -1358,7 +1492,7 @@ function briefToTrace(source) {
|
|
|
1358
1492
|
].join(" · ");
|
|
1359
1493
|
}
|
|
1360
1494
|
/**
|
|
1361
|
-
*
|
|
1495
|
+
* Renders one exemplar as markdown lines.
|
|
1362
1496
|
*
|
|
1363
1497
|
* @remarks
|
|
1364
1498
|
* An `Example`'s two sides are the only brief members permitted to span lines, so a
|
|
@@ -1370,9 +1504,9 @@ function briefToTrace(source) {
|
|
|
1370
1504
|
*
|
|
1371
1505
|
* @example
|
|
1372
1506
|
* ```ts
|
|
1373
|
-
* import {
|
|
1507
|
+
* import { buildExample, exampleToLines } from '@orkestrel/brief'
|
|
1374
1508
|
*
|
|
1375
|
-
* exampleToLines(
|
|
1509
|
+
* exampleToLines(buildExample('<input required>', 'el.validity')) // ['- ` <input required> ` → ` el.validity `']
|
|
1376
1510
|
* ```
|
|
1377
1511
|
*/
|
|
1378
1512
|
function exampleToLines(entry) {
|
|
@@ -1403,20 +1537,21 @@ function exampleToLines(entry) {
|
|
|
1403
1537
|
];
|
|
1404
1538
|
}
|
|
1405
1539
|
/**
|
|
1406
|
-
*
|
|
1540
|
+
* Projects a brief into the copy-ready agent prompt.
|
|
1407
1541
|
*
|
|
1408
1542
|
* @remarks
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1543
|
+
* Sections render in authority order, so the executor meets what wins a conflict before what
|
|
1544
|
+
* it may touch. Paths are referenced, never inlined — the executor retrieves them. An empty
|
|
1545
|
+
* section is omitted entirely, so the rendering carries no filler an executor must read past.
|
|
1411
1546
|
*
|
|
1412
|
-
* @param
|
|
1547
|
+
* @param input - The brief to render.
|
|
1413
1548
|
* @returns The markdown prompt.
|
|
1414
1549
|
*
|
|
1415
1550
|
* @example
|
|
1416
1551
|
* ```ts
|
|
1417
|
-
* import {
|
|
1552
|
+
* import { briefToMarkdown, buildBrief, buildTask } from '@orkestrel/brief'
|
|
1418
1553
|
*
|
|
1419
|
-
* briefToMarkdown(
|
|
1554
|
+
* briefToMarkdown(buildBrief(buildTask('review', 'code', 'Review the gate rules.')))
|
|
1420
1555
|
* // '# Brief: Review the gate rules.\n\nreview · code\n\n## Output\n\n- format: markdown\n'
|
|
1421
1556
|
* ```
|
|
1422
1557
|
*/
|
|
@@ -1510,21 +1645,21 @@ function briefToMarkdown(input) {
|
|
|
1510
1645
|
return lines.join("\n");
|
|
1511
1646
|
}
|
|
1512
1647
|
/**
|
|
1513
|
-
*
|
|
1648
|
+
* Projects a brief into a `/goal` completion condition.
|
|
1514
1649
|
*
|
|
1515
1650
|
* @remarks
|
|
1516
1651
|
* The proofs' commands VERBATIM plus a turn cap — the goal never adds a condition the
|
|
1517
1652
|
* brief does not carry.
|
|
1518
1653
|
*
|
|
1519
|
-
* @param
|
|
1520
|
-
* @param turns - The turn cap
|
|
1654
|
+
* @param input - The brief to render.
|
|
1655
|
+
* @param turns - The turn cap. Default: `DEFAULT_BRIEF_TURNS`.
|
|
1521
1656
|
* @returns The one-line completion condition.
|
|
1522
1657
|
*
|
|
1523
1658
|
* @example
|
|
1524
1659
|
* ```ts
|
|
1525
|
-
* import {
|
|
1660
|
+
* import { briefToGoal, buildBrief, buildProof, buildTask } from '@orkestrel/brief'
|
|
1526
1661
|
*
|
|
1527
|
-
* briefToGoal(
|
|
1662
|
+
* briefToGoal(buildBrief(buildTask('test', 'code', 'Cover the gate.'), { proofs: [buildProof('x', 'npm test')] }))
|
|
1528
1663
|
* // 'Done when every proof passes: npm test exits 0. Cap: 16 turns.'
|
|
1529
1664
|
* ```
|
|
1530
1665
|
*/
|
|
@@ -1533,27 +1668,34 @@ function briefToGoal(input, turns = 16) {
|
|
|
1533
1668
|
return `Done when every proof passes: ${source.proofs.length === 0 ? "no proofs recorded" : source.proofs.map((entry) => `${entry.command} exits 0`).join("; ")}. Cap: ${String(turns)} turns.`;
|
|
1534
1669
|
}
|
|
1535
1670
|
/**
|
|
1536
|
-
*
|
|
1671
|
+
* Projects a brief into a subagent `Dispatch`.
|
|
1537
1672
|
*
|
|
1538
1673
|
* @remarks
|
|
1539
|
-
* `edit` is exactly `manifest.edit
|
|
1540
|
-
* can run concurrently under the same brief without conflict.
|
|
1674
|
+
* `edit` is exactly `manifest.edit` — the owned set — so two dispatches whose `edit` sets do
|
|
1675
|
+
* not intersect can run concurrently under the same brief without conflict. `locked` and
|
|
1676
|
+
* `forbidden` cross unchanged as the do-not-touch sets.
|
|
1541
1677
|
*
|
|
1542
|
-
* `authority` is exactly `brief.authority` in rank order, and it is a
|
|
1543
|
-
*
|
|
1678
|
+
* `authority` is exactly `brief.authority` in rank order, and it is a separate axis from the
|
|
1679
|
+
* permission sets rather than a further partition — a ranked path normally also appears in
|
|
1544
1680
|
* `read` or `locked`, because the executor has to open what it obeys. It is projected as
|
|
1545
1681
|
* paths so a machine consumer never has to parse `prompt`, which is written for a model.
|
|
1546
1682
|
*
|
|
1547
|
-
* @param
|
|
1548
|
-
* @returns The dispatch — the rendered prompt, the ranked authority, and the
|
|
1683
|
+
* @param input - The brief to project.
|
|
1684
|
+
* @returns The dispatch — the rendered prompt, the ranked authority, and the path sets.
|
|
1549
1685
|
*
|
|
1550
1686
|
* @example
|
|
1551
1687
|
* ```ts
|
|
1552
|
-
* import {
|
|
1553
|
-
*
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1556
|
-
*
|
|
1688
|
+
* import {
|
|
1689
|
+
* briefToDispatch,
|
|
1690
|
+
* buildBrief,
|
|
1691
|
+
* buildManifest,
|
|
1692
|
+
* buildReference,
|
|
1693
|
+
* buildTask,
|
|
1694
|
+
* } from '@orkestrel/brief'
|
|
1695
|
+
*
|
|
1696
|
+
* const draft = buildBrief(buildTask('migrate', 'code', 'Migrate the stores.'), {
|
|
1697
|
+
* authority: [buildReference('AGENTS.md', 'project law')],
|
|
1698
|
+
* manifest: buildManifest({ edit: [buildReference('src/core/stores/**', 'the legacy stores')] }),
|
|
1557
1699
|
* })
|
|
1558
1700
|
* briefToDispatch(draft).edit // ['src/core/stores/**']
|
|
1559
1701
|
* briefToDispatch(draft).authority // ['AGENTS.md']
|
|
@@ -1571,36 +1713,39 @@ function briefToDispatch(input) {
|
|
|
1571
1713
|
};
|
|
1572
1714
|
}
|
|
1573
1715
|
/**
|
|
1574
|
-
*
|
|
1716
|
+
* Derives one imperative statement from free text.
|
|
1575
1717
|
*
|
|
1576
1718
|
* @remarks
|
|
1577
1719
|
* Whitespace collapses, the first character uppercases, and a terminator is appended
|
|
1578
1720
|
* when the text carries none. Nothing else is invented.
|
|
1579
1721
|
*
|
|
1580
1722
|
* @param text - The raw request text.
|
|
1581
|
-
* @returns The statement, or `
|
|
1723
|
+
* @returns The statement, or `undefined` for empty or whitespace-only text.
|
|
1582
1724
|
*
|
|
1583
1725
|
* @example
|
|
1584
1726
|
* ```ts
|
|
1585
1727
|
* import { deriveStatement } from '@orkestrel/brief'
|
|
1586
1728
|
*
|
|
1587
1729
|
* deriveStatement(' clean up useForm ') // 'Clean up useForm.'
|
|
1588
|
-
* deriveStatement('') //
|
|
1730
|
+
* deriveStatement('') // undefined
|
|
1589
1731
|
* ```
|
|
1590
1732
|
*/
|
|
1591
1733
|
function deriveStatement(text) {
|
|
1592
1734
|
const collapsed = collapseWhitespace(text);
|
|
1593
|
-
if (collapsed.length === 0) return
|
|
1735
|
+
if (collapsed.length === 0) return void 0;
|
|
1594
1736
|
const capitalized = collapsed.charAt(0).toUpperCase() + collapsed.slice(1);
|
|
1595
1737
|
return /[.!?]$/u.test(capitalized) ? capitalized : `${capitalized}.`;
|
|
1596
1738
|
}
|
|
1597
1739
|
/**
|
|
1598
|
-
*
|
|
1740
|
+
* Derives a `Task` from an interprets `Intent` through the caller's vocabularies.
|
|
1599
1741
|
*
|
|
1600
1742
|
* @remarks
|
|
1601
1743
|
* The vocabularies are the CALLER's policy: this maps and never guesses. An action or
|
|
1602
1744
|
* domain the caller did not map — or mapped to an off-vocabulary value — yields
|
|
1603
|
-
* `undefined` rather than an invented task. Inherited keys never resolve.
|
|
1745
|
+
* `undefined` rather than an invented task. Inherited keys never resolve. `Intent.action`
|
|
1746
|
+
* and `Intent.domain` are optional, because `classifyIntent` leaves an unmatched axis
|
|
1747
|
+
* absent, and an absent axis is unmapped by definition: it yields `undefined` before
|
|
1748
|
+
* either vocabulary is read.
|
|
1604
1749
|
*
|
|
1605
1750
|
* @param intent - The classified intent from an interpret pipeline.
|
|
1606
1751
|
* @param text - The text the statement derives from.
|
|
@@ -1619,16 +1764,17 @@ function deriveStatement(text) {
|
|
|
1619
1764
|
* ```
|
|
1620
1765
|
*/
|
|
1621
1766
|
function deriveTask(intent, text, actions, domains) {
|
|
1767
|
+
if (intent.action === void 0 || intent.domain === void 0) return void 0;
|
|
1622
1768
|
const operationDescriptor = Object.getOwnPropertyDescriptor(actions, intent.action);
|
|
1623
1769
|
const domainDescriptor = Object.getOwnPropertyDescriptor(domains, intent.domain);
|
|
1624
1770
|
const operation = operationDescriptor === void 0 ? void 0 : "value" in operationDescriptor ? operationDescriptor.value : operationDescriptor.get === void 0 ? void 0 : Reflect.apply(operationDescriptor.get, actions, []);
|
|
1625
1771
|
const domain = domainDescriptor === void 0 ? void 0 : "value" in domainDescriptor ? domainDescriptor.value : domainDescriptor.get === void 0 ? void 0 : Reflect.apply(domainDescriptor.get, domains, []);
|
|
1626
1772
|
if (!isTaskOperation(operation) || !isTaskDomain(domain)) return void 0;
|
|
1627
1773
|
const statement = deriveStatement(text);
|
|
1628
|
-
return statement
|
|
1774
|
+
return statement === void 0 ? void 0 : buildTask(operation, domain, statement);
|
|
1629
1775
|
}
|
|
1630
1776
|
/**
|
|
1631
|
-
*
|
|
1777
|
+
* Derives `Given[]` from an interprets `Entity[]`.
|
|
1632
1778
|
*
|
|
1633
1779
|
* @remarks
|
|
1634
1780
|
* Every extracted entity becomes one `extracted` fact. A nameless entity is dropped; an
|
|
@@ -1647,10 +1793,10 @@ function deriveTask(intent, text, actions, domains) {
|
|
|
1647
1793
|
* ```
|
|
1648
1794
|
*/
|
|
1649
1795
|
function deriveGivens(entities) {
|
|
1650
|
-
return entities.filter((entity) => entity.name.length > 0).map((entity) =>
|
|
1796
|
+
return entities.filter((entity) => entity.name.length > 0).map((entity) => buildGiven("extracted", entity.name, typeof entity.value === "string" ? entity.value : typeof entity.value === "object" && entity.value !== null ? canonicalize(entity.value) : String(entity.value)));
|
|
1651
1797
|
}
|
|
1652
1798
|
/**
|
|
1653
|
-
*
|
|
1799
|
+
* Derives `Gap[]` from an interprets `Ambiguity[]`.
|
|
1654
1800
|
*
|
|
1655
1801
|
* @remarks
|
|
1656
1802
|
* A REQUIRED ambiguity becomes a BLOCKING gap — the gate must fail closed on it. The
|
|
@@ -1671,7 +1817,7 @@ function deriveGivens(entities) {
|
|
|
1671
1817
|
function deriveGaps(ambiguities) {
|
|
1672
1818
|
return ambiguities.map((ambiguity) => {
|
|
1673
1819
|
const candidates = ambiguity.candidates.filter((candidate) => candidate.length > 0);
|
|
1674
|
-
return
|
|
1820
|
+
return buildGap(formatField(ambiguity.field), ambiguity.question, {
|
|
1675
1821
|
blocking: ambiguity.required,
|
|
1676
1822
|
...candidates.length === 0 ? {} : { candidates }
|
|
1677
1823
|
});
|
|
@@ -1680,7 +1826,7 @@ function deriveGaps(ambiguities) {
|
|
|
1680
1826
|
//#endregion
|
|
1681
1827
|
//#region src/core/parsers.ts
|
|
1682
1828
|
/**
|
|
1683
|
-
*
|
|
1829
|
+
* Parses a JSON string into a `Brief`.
|
|
1684
1830
|
*
|
|
1685
1831
|
* @remarks
|
|
1686
1832
|
* The parse-then-trust boundary for a stored brief, a tool argument, or an agent's
|
|
@@ -1714,7 +1860,7 @@ function parseBrief(value) {
|
|
|
1714
1860
|
//#endregion
|
|
1715
1861
|
//#region src/core/BriefManager.ts
|
|
1716
1862
|
/**
|
|
1717
|
-
*
|
|
1863
|
+
* Implements the self-owning, versioned and content-hashed brief registry.
|
|
1718
1864
|
*
|
|
1719
1865
|
* @remarks
|
|
1720
1866
|
* Record ids are MINTED from each brief's own content hash unless the caller names one,
|
|
@@ -1724,10 +1870,10 @@ function parseBrief(value) {
|
|
|
1724
1870
|
*
|
|
1725
1871
|
* @example
|
|
1726
1872
|
* ```ts
|
|
1727
|
-
* import { BriefManager,
|
|
1873
|
+
* import { BriefManager, buildBrief, buildTask } from '@orkestrel/brief'
|
|
1728
1874
|
*
|
|
1729
1875
|
* const briefs = new BriefManager()
|
|
1730
|
-
* const record = briefs.add(
|
|
1876
|
+
* const record = briefs.add(buildBrief(buildTask('document', 'writing', 'Write the brief guide.')))
|
|
1731
1877
|
* record.id === record.hash // true
|
|
1732
1878
|
* briefs.destroy()
|
|
1733
1879
|
* ```
|
|
@@ -1754,7 +1900,7 @@ var BriefManager = class {
|
|
|
1754
1900
|
get emitter() {
|
|
1755
1901
|
return this.#emitter;
|
|
1756
1902
|
}
|
|
1757
|
-
get
|
|
1903
|
+
get count() {
|
|
1758
1904
|
return this.#records.size;
|
|
1759
1905
|
}
|
|
1760
1906
|
has(id) {
|
|
@@ -1769,9 +1915,9 @@ var BriefManager = class {
|
|
|
1769
1915
|
this.#refuseDestroyed();
|
|
1770
1916
|
return [...this.#records.values()];
|
|
1771
1917
|
}
|
|
1772
|
-
add(
|
|
1918
|
+
add(brief, options) {
|
|
1773
1919
|
this.#refuseDestroyed();
|
|
1774
|
-
const record = this.#stage(
|
|
1920
|
+
const record = this.#stage(brief, this.#records, options);
|
|
1775
1921
|
this.#commit(record);
|
|
1776
1922
|
return record;
|
|
1777
1923
|
}
|
|
@@ -1838,7 +1984,7 @@ var BriefManager = class {
|
|
|
1838
1984
|
//#endregion
|
|
1839
1985
|
//#region src/core/BriefCompiler.ts
|
|
1840
1986
|
/**
|
|
1841
|
-
*
|
|
1987
|
+
* Implements the compilation orchestrator — the `[interpret, draft, gate, pin]` pipeline.
|
|
1842
1988
|
*
|
|
1843
1989
|
* @remarks
|
|
1844
1990
|
* `compile` is genuinely SYNCHRONOUS and never throws for a brief it cannot emit: a
|
|
@@ -1848,13 +1994,13 @@ var BriefManager = class {
|
|
|
1848
1994
|
*
|
|
1849
1995
|
* @example
|
|
1850
1996
|
* ```ts
|
|
1851
|
-
* import { BriefCompiler,
|
|
1997
|
+
* import { BriefCompiler, buildProof, buildTask } from '@orkestrel/brief'
|
|
1852
1998
|
*
|
|
1853
1999
|
* const compiler = new BriefCompiler()
|
|
1854
2000
|
* const briefing = compiler.compile({
|
|
1855
|
-
* task:
|
|
2001
|
+
* task: buildTask('audit', 'code', 'Audit the barrel for undocumented exports.'),
|
|
1856
2002
|
* outcomes: [{ rank: 1, text: 'every export appears in the guide', required: true }],
|
|
1857
|
-
* proofs: [
|
|
2003
|
+
* proofs: [buildProof('parity passes', 'npm run test:guides')],
|
|
1858
2004
|
* })
|
|
1859
2005
|
* briefing.brief !== undefined // true — the presence of the brief IS the completeness test
|
|
1860
2006
|
* compiler.destroy()
|
|
@@ -2005,9 +2151,9 @@ var BriefCompiler = class {
|
|
|
2005
2151
|
this.#emitter.emit("compile", briefing);
|
|
2006
2152
|
return briefing;
|
|
2007
2153
|
}
|
|
2008
|
-
gate(
|
|
2154
|
+
gate(brief) {
|
|
2009
2155
|
this.#refuseDestroyed();
|
|
2010
|
-
const ruled = attempt(() => this.#own(this.#reason.reason(briefToSubject(
|
|
2156
|
+
const ruled = attempt(() => this.#own(this.#reason.reason(briefToSubject(brief), buildGateDefinition()), [
|
|
2011
2157
|
"reasoning",
|
|
2012
2158
|
"conclusion",
|
|
2013
2159
|
"rules",
|
|
@@ -2096,7 +2242,7 @@ var BriefCompiler = class {
|
|
|
2096
2242
|
message: `Gate refused: ${unready.join(", ")}`
|
|
2097
2243
|
};
|
|
2098
2244
|
if (verdict === void 0) return void 0;
|
|
2099
|
-
const refused = verdict.rules.filter((entry) => !entry.
|
|
2245
|
+
const refused = verdict.rules.filter((entry) => !entry.applied).map((entry) => entry.id).join(", ");
|
|
2100
2246
|
if (refused.length === 0) return {
|
|
2101
2247
|
stage: "gate",
|
|
2102
2248
|
code: "BLOCKED",
|
|
@@ -2111,7 +2257,7 @@ var BriefCompiler = class {
|
|
|
2111
2257
|
#unresolved(interpretation, failures) {
|
|
2112
2258
|
if (interpretation !== void 0) return [];
|
|
2113
2259
|
if (!failures.some((entry) => entry.stage === "interpret")) return [];
|
|
2114
|
-
return [
|
|
2260
|
+
return [buildGap("gaps", "The interpret stage failed, so the request is unread and its unknowns are unknown", { blocking: true })];
|
|
2115
2261
|
}
|
|
2116
2262
|
#draft(input, interpretation, unresolved) {
|
|
2117
2263
|
const derived = interpretation === void 0 ? void 0 : deriveTask(interpretation.intent, interpretation.text, this.#actions, this.#domains);
|
|
@@ -2120,9 +2266,9 @@ var BriefCompiler = class {
|
|
|
2120
2266
|
stage: "draft",
|
|
2121
2267
|
field: "task"
|
|
2122
2268
|
});
|
|
2123
|
-
return snapshotBrief(
|
|
2269
|
+
return snapshotBrief(buildBrief(subject, {
|
|
2124
2270
|
authority: input.authority ?? [],
|
|
2125
|
-
manifest: input.manifest ??
|
|
2271
|
+
manifest: input.manifest ?? buildManifest(),
|
|
2126
2272
|
outcomes: input.outcomes ?? [],
|
|
2127
2273
|
rules: input.rules ?? [],
|
|
2128
2274
|
invariants: input.invariants ?? [],
|
|
@@ -2136,7 +2282,7 @@ var BriefCompiler = class {
|
|
|
2136
2282
|
...input.gaps ?? []
|
|
2137
2283
|
],
|
|
2138
2284
|
risks: input.risks ?? [],
|
|
2139
|
-
output: input.output ??
|
|
2285
|
+
output: input.output ?? buildOutput("markdown"),
|
|
2140
2286
|
proofs: input.proofs ?? []
|
|
2141
2287
|
}));
|
|
2142
2288
|
}
|
|
@@ -2164,7 +2310,7 @@ var BriefCompiler = class {
|
|
|
2164
2310
|
//#endregion
|
|
2165
2311
|
//#region src/core/factories.ts
|
|
2166
2312
|
/**
|
|
2167
|
-
*
|
|
2313
|
+
* Creates a compilation orchestrator.
|
|
2168
2314
|
*
|
|
2169
2315
|
* @remarks
|
|
2170
2316
|
* With no engines supplied the compiler wires its own: a default `createInterpret()`
|
|
@@ -2172,9 +2318,49 @@ var BriefCompiler = class {
|
|
|
2172
2318
|
* `createReason` carrying one `LogicalReasoner` for the gate. Pass your own to share
|
|
2173
2319
|
* instances or observe their emitters — the compiler destroys ONLY what it created.
|
|
2174
2320
|
*
|
|
2175
|
-
* @param options - Engines to borrow, the
|
|
2321
|
+
* @param options - Engines to borrow, the `actions` and `domains` intent vocabularies, and
|
|
2322
|
+
* emitter hooks.
|
|
2176
2323
|
* @returns A working {@link BriefCompilerInterface}.
|
|
2177
2324
|
*
|
|
2325
|
+
* @example Compile and project a brief
|
|
2326
|
+
* ```ts
|
|
2327
|
+
* import {
|
|
2328
|
+
* briefToGoal,
|
|
2329
|
+
* briefToMarkdown,
|
|
2330
|
+
* buildOutcome,
|
|
2331
|
+
* buildProof,
|
|
2332
|
+
* buildTask,
|
|
2333
|
+
* createBriefCompiler,
|
|
2334
|
+
* } from '@orkestrel/brief'
|
|
2335
|
+
*
|
|
2336
|
+
* const compiler = createBriefCompiler()
|
|
2337
|
+
*
|
|
2338
|
+
* const briefing = compiler.compile({
|
|
2339
|
+
* task: buildTask('refactor', 'code', 'Refactor useForm to native browser form APIs.'),
|
|
2340
|
+
* authority: [{ path: 'AGENTS.md', note: 'project law; wins every conflict' }],
|
|
2341
|
+
* manifest: {
|
|
2342
|
+
* read: [
|
|
2343
|
+
* { path: 'AGENTS.md', note: 'project law; wins every conflict' },
|
|
2344
|
+
* { path: 'guides/browser.md', note: 'the composable contract' },
|
|
2345
|
+
* ],
|
|
2346
|
+
* edit: [{ path: 'src/browser/composables/useForm.ts', note: 'the composable being refactored' }],
|
|
2347
|
+
* locked: [{ path: 'src/browser/types.ts', note: 'the published contract' }],
|
|
2348
|
+
* forbidden: [{ path: 'app/**', note: 'out of scope' }],
|
|
2349
|
+
* },
|
|
2350
|
+
* outcomes: [buildOutcome(1, 'useForm uses native FormData with no behavior change')],
|
|
2351
|
+
* proofs: [buildProof('type-check and lint pass', 'npm run check')],
|
|
2352
|
+
* })
|
|
2353
|
+
*
|
|
2354
|
+
* briefing.brief !== undefined // true — the brief is present exactly when the gate passed
|
|
2355
|
+
* if (briefing.brief !== undefined) {
|
|
2356
|
+
* briefToMarkdown(briefing.brief) // the copy-ready agent prompt
|
|
2357
|
+
* briefToGoal(briefing.brief) // the /goal completion condition
|
|
2358
|
+
* }
|
|
2359
|
+
*
|
|
2360
|
+
* compiler.emitter.on('block', (questions) => questions.length)
|
|
2361
|
+
* compiler.destroy()
|
|
2362
|
+
* ```
|
|
2363
|
+
*
|
|
2178
2364
|
* @example
|
|
2179
2365
|
* ```ts
|
|
2180
2366
|
* import { createBriefCompiler } from '@orkestrel/brief'
|
|
@@ -2187,7 +2373,7 @@ function createBriefCompiler(options) {
|
|
|
2187
2373
|
return new BriefCompiler(options);
|
|
2188
2374
|
}
|
|
2189
2375
|
/**
|
|
2190
|
-
*
|
|
2376
|
+
* Creates a brief registry.
|
|
2191
2377
|
*
|
|
2192
2378
|
* @param options - An optional seed collection plus emitter hooks.
|
|
2193
2379
|
* @returns A working {@link BriefManagerInterface}.
|
|
@@ -2197,7 +2383,7 @@ function createBriefCompiler(options) {
|
|
|
2197
2383
|
* import { createBriefManager } from '@orkestrel/brief'
|
|
2198
2384
|
*
|
|
2199
2385
|
* const briefs = createBriefManager()
|
|
2200
|
-
* briefs.
|
|
2386
|
+
* briefs.count // 0
|
|
2201
2387
|
* briefs.destroy()
|
|
2202
2388
|
* ```
|
|
2203
2389
|
*/
|
|
@@ -2205,7 +2391,7 @@ function createBriefManager(options) {
|
|
|
2205
2391
|
return new BriefManager(options);
|
|
2206
2392
|
}
|
|
2207
2393
|
/**
|
|
2208
|
-
*
|
|
2394
|
+
* Compiles `briefShape` into a guard, parser, JSON Schema, and seeded generator bundle.
|
|
2209
2395
|
*
|
|
2210
2396
|
* @remarks
|
|
2211
2397
|
* The schema is what a tool boundary needs — hand it to `schemaToParameters` — and
|
|
@@ -2229,6 +2415,6 @@ function createBriefContract() {
|
|
|
2229
2415
|
return createContract(briefShape);
|
|
2230
2416
|
}
|
|
2231
2417
|
//#endregion
|
|
2232
|
-
export { BLANK_PATTERN, BriefCompiler, BriefError, BriefManager, DEFAULT_BRIEF_TURNS, GATE_ID, INTERPRETATION_MEMBERS, LINE_BREAK_PATTERN, OUTPUT_FORMATS, RISK_SEVERITIES, SINGLE_LINE_PATTERN, TASK_DOMAINS, TASK_OPERATIONS, assertBrief,
|
|
2418
|
+
export { BLANK_PATTERN, BriefCompiler, BriefError, BriefManager, DEFAULT_BRIEF_TURNS, GATE_ID, INTERPRETATION_MEMBERS, LINE_BREAK_PATTERN, OUTPUT_FORMATS, RISK_SEVERITIES, SINGLE_LINE_PATTERN, TASK_DOMAINS, TASK_OPERATIONS, assertBrief, briefShape, briefToContent, briefToDispatch, briefToGoal, briefToHash, briefToMarkdown, briefToSubject, briefToTrace, buildBrief, buildCitation, buildExample, buildGap, buildGateDefinition, buildGiven, buildManifest, buildOutcome, buildOutput, buildProof, buildReference, buildRisk, buildTask, captureValue, citationShape, countSentences, createBriefCompiler, createBriefContract, createBriefManager, deriveGaps, deriveGivens, deriveStatement, deriveTask, errorToMessage, exampleShape, exampleToLines, findBlockingGaps, findManifestOverlaps, findUngrantedAuthority, findUnmetRules, findUnpairedGaps, freezeBranch, freezeDeep, gapShape, givenShape, isBrief, isBriefError, isCitation, isExample, isGap, isGiven, isLine, isManifest, isOutcome, isOutput, isOutputFormat, isProof, isReference, isRisk, isRiskSeverity, isTask, isTaskDomain, isTaskOperation, isText, lineShape, manifestShape, outcomeShape, outputShape, parseBrief, pinBrief, proofShape, referenceShape, riskShape, snapshotBrief, taskShape, textShape, validateBrief };
|
|
2233
2419
|
|
|
2234
2420
|
//# sourceMappingURL=index.js.map
|