@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/dist/src/core/index.js
CHANGED
|
@@ -3,7 +3,13 @@ import { canonicalize, collapseWhitespace, createInterpret, digestValue, isInter
|
|
|
3
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",
|
|
@@ -86,7 +92,7 @@ var GATE_ID = "gate";
|
|
|
86
92
|
* Matches every line terminator a brief field refuses.
|
|
87
93
|
*
|
|
88
94
|
* @remarks
|
|
89
|
-
* Every ECMAScript line terminator, not
|
|
95
|
+
* Every ECMAScript line terminator, not only `\n`: a renderer that splits on any of them
|
|
90
96
|
* would let the others forge a markdown row. CRLF leads the alternation so a Windows
|
|
91
97
|
* exemplar splits as ONE break rather than two, which would insert a blank line the caller
|
|
92
98
|
* never wrote. Kept unanchored and stateless — no `g` flag — so `test` never carries
|
|
@@ -94,7 +100,7 @@ var GATE_ID = "gate";
|
|
|
94
100
|
*/
|
|
95
101
|
var LINE_BREAK_PATTERN = /\r\n|[\n\r\u2028\u2029]/;
|
|
96
102
|
/**
|
|
97
|
-
* Holds the positive form of {@link LINE_BREAK_PATTERN}, for
|
|
103
|
+
* Holds the positive form of {@link LINE_BREAK_PATTERN}, for a `stringShape` `pattern`.
|
|
98
104
|
*
|
|
99
105
|
* @remarks
|
|
100
106
|
* `stringShape`'s `pattern` must MATCH an accepted value, so the guard's refusal regex
|
|
@@ -120,6 +126,9 @@ var BLANK_PATTERN = /^ +$/;
|
|
|
120
126
|
* Represents the one error class this package throws.
|
|
121
127
|
*
|
|
122
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
|
+
*
|
|
123
132
|
* Throws are reserved for caller misuse: `assertBrief`, `snapshotBrief`, and `pinBrief` on
|
|
124
133
|
* off-contract data throw `INVALID`; any method after `destroy()` throws `DESTROYED`; and `BriefCompiler.gate` throws
|
|
125
134
|
* `GATE_FAILED` when a borrowed reasoner returns a non-logical result. A stage that fails
|
|
@@ -168,14 +177,21 @@ function isBriefError(value) {
|
|
|
168
177
|
}
|
|
169
178
|
//#endregion
|
|
170
179
|
//#region src/core/shapers.ts
|
|
171
|
-
/** Describes a single-line string of any length, including empty
|
|
180
|
+
/** Describes a single-line string of any length, including empty — the shape mirror of `isText`. */
|
|
172
181
|
var textShape = stringShape({ pattern: SINGLE_LINE_PATTERN });
|
|
173
182
|
/** Describes a non-empty single-line string — the shape mirror of `isLine`. */
|
|
174
183
|
var lineShape = stringShape({
|
|
175
184
|
min: 1,
|
|
176
185
|
pattern: SINGLE_LINE_PATTERN
|
|
177
186
|
});
|
|
178
|
-
/**
|
|
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
|
+
*/
|
|
179
195
|
var taskShape = objectShape({
|
|
180
196
|
operation: literalShape(TASK_OPERATIONS),
|
|
181
197
|
domain: literalShape(TASK_DOMAINS),
|
|
@@ -186,14 +202,25 @@ var referenceShape = objectShape({
|
|
|
186
202
|
path: lineShape,
|
|
187
203
|
note: lineShape
|
|
188
204
|
}, { description: "One referenced path and why it is listed." });
|
|
189
|
-
/**
|
|
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
|
+
*/
|
|
190
212
|
var manifestShape = objectShape({
|
|
191
213
|
read: arrayShape(referenceShape),
|
|
192
214
|
edit: arrayShape(referenceShape),
|
|
193
215
|
locked: arrayShape(referenceShape),
|
|
194
216
|
forbidden: arrayShape(referenceShape)
|
|
195
217
|
}, { description: "The disjoint file partitions of a brief." });
|
|
196
|
-
/**
|
|
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
|
+
*/
|
|
197
224
|
var outcomeShape = objectShape({
|
|
198
225
|
rank: integerShape({ min: 1 }),
|
|
199
226
|
text: lineShape,
|
|
@@ -285,6 +312,10 @@ var isText = (value) => isString(value) && !LINE_BREAK_PATTERN.test(value);
|
|
|
285
312
|
/**
|
|
286
313
|
* Checks whether the value is a non-empty string holding no line terminator.
|
|
287
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
|
+
*
|
|
288
319
|
* @param value - The value to inspect.
|
|
289
320
|
* @returns True if `value` is a non-empty string holding no line terminator; false otherwise.
|
|
290
321
|
*/
|
|
@@ -623,6 +654,10 @@ function buildTask(operation, domain, statement) {
|
|
|
623
654
|
/**
|
|
624
655
|
* Assembles a `Reference` from a path and the note that justifies listing it.
|
|
625
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.
|
|
660
|
+
*
|
|
626
661
|
* @param path - The referenced path or glob.
|
|
627
662
|
* @param note - Why the path is listed.
|
|
628
663
|
* @returns A fresh `Reference`.
|
|
@@ -1009,6 +1044,10 @@ function countSentences(statement) {
|
|
|
1009
1044
|
/**
|
|
1010
1045
|
* Lists the gaps that block emission.
|
|
1011
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.
|
|
1050
|
+
*
|
|
1012
1051
|
* @param source - The brief to inspect.
|
|
1013
1052
|
* @returns Every gap carrying `blocking: true`, in declaration order.
|
|
1014
1053
|
*
|
|
@@ -1037,7 +1076,7 @@ function findBlockingGaps(source) {
|
|
|
1037
1076
|
* are disjoint — `findManifestOverlaps` and the `disjoint` rule enforce it — so a forbidden
|
|
1038
1077
|
* path is in none of the grants and is reported here. An authority named in NO partition at
|
|
1039
1078
|
* all is reported for the same reason, and that is the case a forbidden-only check misses
|
|
1040
|
-
* entirely: the brief
|
|
1079
|
+
* entirely: the brief never says the executor may open what it must obey.
|
|
1041
1080
|
*
|
|
1042
1081
|
* Paths are compared as EXACT strings, matching `findManifestOverlaps`. A glob is never
|
|
1043
1082
|
* expanded, so `read: 'guides/**'` does not grant `authority: 'guides/brief.md'`. State a
|
|
@@ -1501,8 +1540,9 @@ function exampleToLines(entry) {
|
|
|
1501
1540
|
* Projects a brief into the copy-ready agent prompt.
|
|
1502
1541
|
*
|
|
1503
1542
|
* @remarks
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
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.
|
|
1506
1546
|
*
|
|
1507
1547
|
* @param input - The brief to render.
|
|
1508
1548
|
* @returns The markdown prompt.
|
|
@@ -1631,10 +1671,11 @@ function briefToGoal(input, turns = 16) {
|
|
|
1631
1671
|
* Projects a brief into a subagent `Dispatch`.
|
|
1632
1672
|
*
|
|
1633
1673
|
* @remarks
|
|
1634
|
-
* `edit` is exactly `manifest.edit
|
|
1635
|
-
* 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.
|
|
1636
1677
|
*
|
|
1637
|
-
* `authority` is exactly `brief.authority` in rank order, and it is a
|
|
1678
|
+
* `authority` is exactly `brief.authority` in rank order, and it is a separate axis from the
|
|
1638
1679
|
* permission sets rather than a further partition — a ranked path normally also appears in
|
|
1639
1680
|
* `read` or `locked`, because the executor has to open what it obeys. It is projected as
|
|
1640
1681
|
* paths so a machine consumer never has to parse `prompt`, which is written for a model.
|
|
@@ -2281,6 +2322,45 @@ var BriefCompiler = class {
|
|
|
2281
2322
|
* emitter hooks.
|
|
2282
2323
|
* @returns A working {@link BriefCompilerInterface}.
|
|
2283
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
|
+
*
|
|
2284
2364
|
* @example
|
|
2285
2365
|
* ```ts
|
|
2286
2366
|
* import { createBriefCompiler } from '@orkestrel/brief'
|