@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.
@@ -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
- /** Lists the `TaskOperation` values, frozen. */
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 just `\n`: a renderer that splits on any of them
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 the shape DSL.
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
- /** Describes the `Task` shape — closed operation and domain vocabularies plus a non-empty statement. */
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
- /** Describes the `Manifest` shape — disjoint reference partitions. */
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
- /** Describes the `Outcome` shape — a one-based rank, the result text, and whether it gates done. */
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 simply never says the executor may open what it must obey.
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
- * Paths are REFERENCED, never inlined the executor retrieves them. An empty section is
1505
- * omitted entirely, so the rendering carries no filler an executor must read past.
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`, so two dispatches whose `edit` sets do not intersect
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 SEPARATE axis from the
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'