@orkestrel/brief 0.0.7 → 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 +20 -6
- package/dist/src/core/index.cjs +93 -13
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +332 -165
- package/dist/src/core/index.d.ts +332 -165
- package/dist/src/core/index.js +93 -13
- package/dist/src/core/index.js.map +1 -1
- package/package.json +15 -16
package/README.md
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
# @orkestrel/brief
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
`Brief` — a closed,
|
|
5
|
-
interpretation left to do —
|
|
6
|
-
|
|
3
|
+
> The specification compiler: a synchronous, deterministic pipeline that resolves a rough
|
|
4
|
+
> request into a `Brief` — a closed, content-hashed execution contract another agent can run
|
|
5
|
+
> with no interpretation left to do — gated by a traceable reasoner and projected into every
|
|
6
|
+
> downstream artifact.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Compile a request with the `createBriefCompiler` factory, read the `Briefing` it returns, and
|
|
9
|
+
project the brief it carries into the prompt a model reads, a completion condition, or a
|
|
10
|
+
subagent dispatch. A brief with blocking gaps never emits: the readiness gate is a
|
|
11
|
+
`@orkestrel/reason` `LogicalDefinition`, so every verdict carries a traceable account of which
|
|
12
|
+
check missed. Part of the `@orkestrel` line.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
10
15
|
|
|
11
16
|
```sh
|
|
12
17
|
npm install @orkestrel/brief
|
|
13
18
|
```
|
|
14
19
|
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- Node.js >= 22.12.0, matching the `engines` field in `package.json`
|
|
23
|
+
- ESM and CommonJS entry points, selected by the `exports` field in `package.json`
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
15
27
|
```ts
|
|
16
28
|
import {
|
|
17
29
|
createBriefCompiler,
|
|
@@ -36,6 +48,8 @@ if (briefing.brief !== undefined) {
|
|
|
36
48
|
compiler.destroy()
|
|
37
49
|
```
|
|
38
50
|
|
|
51
|
+
## Guide
|
|
52
|
+
|
|
39
53
|
Full documentation: [`guides/brief.md`](guides/brief.md). The guides index lives at
|
|
40
54
|
[`guides/README.md`](guides/README.md).
|
|
41
55
|
|
package/dist/src/core/index.cjs
CHANGED
|
@@ -4,7 +4,13 @@ let _orkestrel_interpret = require("@orkestrel/interpret");
|
|
|
4
4
|
let _orkestrel_reason = require("@orkestrel/reason");
|
|
5
5
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
6
6
|
//#region src/core/constants.ts
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Lists the `TaskOperation` values, frozen.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Compose the tuple rather than restating its members: `literalOf(TASK_OPERATIONS)` builds the
|
|
12
|
+
* guard and `parseEnum(value, TASK_OPERATIONS)` coerces a bare value against it.
|
|
13
|
+
*/
|
|
8
14
|
var TASK_OPERATIONS = Object.freeze([
|
|
9
15
|
"create",
|
|
10
16
|
"refactor",
|
|
@@ -87,7 +93,7 @@ var GATE_ID = "gate";
|
|
|
87
93
|
* Matches every line terminator a brief field refuses.
|
|
88
94
|
*
|
|
89
95
|
* @remarks
|
|
90
|
-
* Every ECMAScript line terminator, not
|
|
96
|
+
* Every ECMAScript line terminator, not only `\n`: a renderer that splits on any of them
|
|
91
97
|
* would let the others forge a markdown row. CRLF leads the alternation so a Windows
|
|
92
98
|
* exemplar splits as ONE break rather than two, which would insert a blank line the caller
|
|
93
99
|
* never wrote. Kept unanchored and stateless — no `g` flag — so `test` never carries
|
|
@@ -95,7 +101,7 @@ var GATE_ID = "gate";
|
|
|
95
101
|
*/
|
|
96
102
|
var LINE_BREAK_PATTERN = /\r\n|[\n\r\u2028\u2029]/;
|
|
97
103
|
/**
|
|
98
|
-
* Holds the positive form of {@link LINE_BREAK_PATTERN}, for
|
|
104
|
+
* Holds the positive form of {@link LINE_BREAK_PATTERN}, for a `stringShape` `pattern`.
|
|
99
105
|
*
|
|
100
106
|
* @remarks
|
|
101
107
|
* `stringShape`'s `pattern` must MATCH an accepted value, so the guard's refusal regex
|
|
@@ -121,6 +127,9 @@ var BLANK_PATTERN = /^ +$/;
|
|
|
121
127
|
* Represents the one error class this package throws.
|
|
122
128
|
*
|
|
123
129
|
* @remarks
|
|
130
|
+
* Extends `Error` with a readonly `code` on the `BriefErrorCode` vocabulary and an optional
|
|
131
|
+
* readonly `context` record carrying whatever the raising site can supply.
|
|
132
|
+
*
|
|
124
133
|
* Throws are reserved for caller misuse: `assertBrief`, `snapshotBrief`, and `pinBrief` on
|
|
125
134
|
* off-contract data throw `INVALID`; any method after `destroy()` throws `DESTROYED`; and `BriefCompiler.gate` throws
|
|
126
135
|
* `GATE_FAILED` when a borrowed reasoner returns a non-logical result. A stage that fails
|
|
@@ -169,14 +178,21 @@ function isBriefError(value) {
|
|
|
169
178
|
}
|
|
170
179
|
//#endregion
|
|
171
180
|
//#region src/core/shapers.ts
|
|
172
|
-
/** Describes a single-line string of any length, including empty
|
|
181
|
+
/** Describes a single-line string of any length, including empty — the shape mirror of `isText`. */
|
|
173
182
|
var textShape = (0, _orkestrel_contract.stringShape)({ pattern: SINGLE_LINE_PATTERN });
|
|
174
183
|
/** Describes a non-empty single-line string — the shape mirror of `isLine`. */
|
|
175
184
|
var lineShape = (0, _orkestrel_contract.stringShape)({
|
|
176
185
|
min: 1,
|
|
177
186
|
pattern: SINGLE_LINE_PATTERN
|
|
178
187
|
});
|
|
179
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* Describes the `Task` shape — closed operation and domain vocabularies plus a non-empty
|
|
190
|
+
* statement.
|
|
191
|
+
*
|
|
192
|
+
* @remarks
|
|
193
|
+
* `literalShape(TASK_OPERATIONS)` and `literalShape(TASK_DOMAINS)` compile the same tuples the
|
|
194
|
+
* guards read, and `statement` carries `min: 1`.
|
|
195
|
+
*/
|
|
180
196
|
var taskShape = (0, _orkestrel_contract.objectShape)({
|
|
181
197
|
operation: (0, _orkestrel_contract.literalShape)(TASK_OPERATIONS),
|
|
182
198
|
domain: (0, _orkestrel_contract.literalShape)(TASK_DOMAINS),
|
|
@@ -187,14 +203,25 @@ var referenceShape = (0, _orkestrel_contract.objectShape)({
|
|
|
187
203
|
path: lineShape,
|
|
188
204
|
note: lineShape
|
|
189
205
|
}, { description: "One referenced path and why it is listed." });
|
|
190
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Describes the `Manifest` shape — disjoint reference partitions.
|
|
208
|
+
*
|
|
209
|
+
* @remarks
|
|
210
|
+
* Each partition is an `arrayShape(referenceShape)`; disjointness is `validateBrief`'s pass
|
|
211
|
+
* rather than the shape's.
|
|
212
|
+
*/
|
|
191
213
|
var manifestShape = (0, _orkestrel_contract.objectShape)({
|
|
192
214
|
read: (0, _orkestrel_contract.arrayShape)(referenceShape),
|
|
193
215
|
edit: (0, _orkestrel_contract.arrayShape)(referenceShape),
|
|
194
216
|
locked: (0, _orkestrel_contract.arrayShape)(referenceShape),
|
|
195
217
|
forbidden: (0, _orkestrel_contract.arrayShape)(referenceShape)
|
|
196
218
|
}, { description: "The disjoint file partitions of a brief." });
|
|
197
|
-
/**
|
|
219
|
+
/**
|
|
220
|
+
* Describes the `Outcome` shape — a one-based rank, the result text, and whether it gates done.
|
|
221
|
+
*
|
|
222
|
+
* @remarks
|
|
223
|
+
* `rank` is an `integerShape({ min: 1 })`, so a zero or fractional rank is off-contract.
|
|
224
|
+
*/
|
|
198
225
|
var outcomeShape = (0, _orkestrel_contract.objectShape)({
|
|
199
226
|
rank: (0, _orkestrel_contract.integerShape)({ min: 1 }),
|
|
200
227
|
text: lineShape,
|
|
@@ -286,6 +313,10 @@ var isText = (value) => (0, _orkestrel_contract.isString)(value) && !LINE_BREAK_
|
|
|
286
313
|
/**
|
|
287
314
|
* Checks whether the value is a non-empty string holding no line terminator.
|
|
288
315
|
*
|
|
316
|
+
* @remarks
|
|
317
|
+
* The shape of nearly every brief field: a path, a note, a statement, a rule, and a command
|
|
318
|
+
* all narrow through it.
|
|
319
|
+
*
|
|
289
320
|
* @param value - The value to inspect.
|
|
290
321
|
* @returns True if `value` is a non-empty string holding no line terminator; false otherwise.
|
|
291
322
|
*/
|
|
@@ -624,6 +655,10 @@ function buildTask(operation, domain, statement) {
|
|
|
624
655
|
/**
|
|
625
656
|
* Assembles a `Reference` from a path and the note that justifies listing it.
|
|
626
657
|
*
|
|
658
|
+
* @remarks
|
|
659
|
+
* The one builder for an authority entry and a manifest entry alike: the container the record
|
|
660
|
+
* lands in is what says whether the path is ranked or permitted.
|
|
661
|
+
*
|
|
627
662
|
* @param path - The referenced path or glob.
|
|
628
663
|
* @param note - Why the path is listed.
|
|
629
664
|
* @returns A fresh `Reference`.
|
|
@@ -1010,6 +1045,10 @@ function countSentences(statement) {
|
|
|
1010
1045
|
/**
|
|
1011
1046
|
* Lists the gaps that block emission.
|
|
1012
1047
|
*
|
|
1048
|
+
* @remarks
|
|
1049
|
+
* A non-empty result means the gate must fail closed: a blocking gap has no safe default, so
|
|
1050
|
+
* the compile yields a visible incomplete `Briefing` carrying the questions instead of a brief.
|
|
1051
|
+
*
|
|
1013
1052
|
* @param source - The brief to inspect.
|
|
1014
1053
|
* @returns Every gap carrying `blocking: true`, in declaration order.
|
|
1015
1054
|
*
|
|
@@ -1038,7 +1077,7 @@ function findBlockingGaps(source) {
|
|
|
1038
1077
|
* are disjoint — `findManifestOverlaps` and the `disjoint` rule enforce it — so a forbidden
|
|
1039
1078
|
* path is in none of the grants and is reported here. An authority named in NO partition at
|
|
1040
1079
|
* all is reported for the same reason, and that is the case a forbidden-only check misses
|
|
1041
|
-
* entirely: the brief
|
|
1080
|
+
* entirely: the brief never says the executor may open what it must obey.
|
|
1042
1081
|
*
|
|
1043
1082
|
* Paths are compared as EXACT strings, matching `findManifestOverlaps`. A glob is never
|
|
1044
1083
|
* expanded, so `read: 'guides/**'` does not grant `authority: 'guides/brief.md'`. State a
|
|
@@ -1502,8 +1541,9 @@ function exampleToLines(entry) {
|
|
|
1502
1541
|
* Projects a brief into the copy-ready agent prompt.
|
|
1503
1542
|
*
|
|
1504
1543
|
* @remarks
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1544
|
+
* Sections render in authority order, so the executor meets what wins a conflict before what
|
|
1545
|
+
* it may touch. Paths are referenced, never inlined — the executor retrieves them. An empty
|
|
1546
|
+
* section is omitted entirely, so the rendering carries no filler an executor must read past.
|
|
1507
1547
|
*
|
|
1508
1548
|
* @param input - The brief to render.
|
|
1509
1549
|
* @returns The markdown prompt.
|
|
@@ -1632,10 +1672,11 @@ function briefToGoal(input, turns = 16) {
|
|
|
1632
1672
|
* Projects a brief into a subagent `Dispatch`.
|
|
1633
1673
|
*
|
|
1634
1674
|
* @remarks
|
|
1635
|
-
* `edit` is exactly `manifest.edit
|
|
1636
|
-
* can run concurrently under the same brief without conflict.
|
|
1675
|
+
* `edit` is exactly `manifest.edit` — the owned set — so two dispatches whose `edit` sets do
|
|
1676
|
+
* not intersect can run concurrently under the same brief without conflict. `locked` and
|
|
1677
|
+
* `forbidden` cross unchanged as the do-not-touch sets.
|
|
1637
1678
|
*
|
|
1638
|
-
* `authority` is exactly `brief.authority` in rank order, and it is a
|
|
1679
|
+
* `authority` is exactly `brief.authority` in rank order, and it is a separate axis from the
|
|
1639
1680
|
* permission sets rather than a further partition — a ranked path normally also appears in
|
|
1640
1681
|
* `read` or `locked`, because the executor has to open what it obeys. It is projected as
|
|
1641
1682
|
* paths so a machine consumer never has to parse `prompt`, which is written for a model.
|
|
@@ -2282,6 +2323,45 @@ var BriefCompiler = class {
|
|
|
2282
2323
|
* emitter hooks.
|
|
2283
2324
|
* @returns A working {@link BriefCompilerInterface}.
|
|
2284
2325
|
*
|
|
2326
|
+
* @example Compile and project a brief
|
|
2327
|
+
* ```ts
|
|
2328
|
+
* import {
|
|
2329
|
+
* briefToGoal,
|
|
2330
|
+
* briefToMarkdown,
|
|
2331
|
+
* buildOutcome,
|
|
2332
|
+
* buildProof,
|
|
2333
|
+
* buildTask,
|
|
2334
|
+
* createBriefCompiler,
|
|
2335
|
+
* } from '@orkestrel/brief'
|
|
2336
|
+
*
|
|
2337
|
+
* const compiler = createBriefCompiler()
|
|
2338
|
+
*
|
|
2339
|
+
* const briefing = compiler.compile({
|
|
2340
|
+
* task: buildTask('refactor', 'code', 'Refactor useForm to native browser form APIs.'),
|
|
2341
|
+
* authority: [{ path: 'AGENTS.md', note: 'project law; wins every conflict' }],
|
|
2342
|
+
* manifest: {
|
|
2343
|
+
* read: [
|
|
2344
|
+
* { path: 'AGENTS.md', note: 'project law; wins every conflict' },
|
|
2345
|
+
* { path: 'guides/browser.md', note: 'the composable contract' },
|
|
2346
|
+
* ],
|
|
2347
|
+
* edit: [{ path: 'src/browser/composables/useForm.ts', note: 'the composable being refactored' }],
|
|
2348
|
+
* locked: [{ path: 'src/browser/types.ts', note: 'the published contract' }],
|
|
2349
|
+
* forbidden: [{ path: 'app/**', note: 'out of scope' }],
|
|
2350
|
+
* },
|
|
2351
|
+
* outcomes: [buildOutcome(1, 'useForm uses native FormData with no behavior change')],
|
|
2352
|
+
* proofs: [buildProof('type-check and lint pass', 'npm run check')],
|
|
2353
|
+
* })
|
|
2354
|
+
*
|
|
2355
|
+
* briefing.brief !== undefined // true — the brief is present exactly when the gate passed
|
|
2356
|
+
* if (briefing.brief !== undefined) {
|
|
2357
|
+
* briefToMarkdown(briefing.brief) // the copy-ready agent prompt
|
|
2358
|
+
* briefToGoal(briefing.brief) // the /goal completion condition
|
|
2359
|
+
* }
|
|
2360
|
+
*
|
|
2361
|
+
* compiler.emitter.on('block', (questions) => questions.length)
|
|
2362
|
+
* compiler.destroy()
|
|
2363
|
+
* ```
|
|
2364
|
+
*
|
|
2285
2365
|
* @example
|
|
2286
2366
|
* ```ts
|
|
2287
2367
|
* import { createBriefCompiler } from '@orkestrel/brief'
|