@jawache/flow 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -9
- package/dist/flow.mjs +94 -73
- package/dist/index.mjs +22 -16
- package/dist/packs.mjs +103 -68
- package/dist/types/adapter/archive.d.ts +8 -1
- package/dist/types/adapter/claude.d.ts +46 -5
- package/dist/types/adapter/domain.d.ts +369 -9
- package/dist/types/checks/domain.d.ts +111 -16
- package/dist/types/engine/domain.d.ts +10 -2
- package/dist/types/glob.d.ts +17 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/language/domain.d.ts +42 -1
- package/dist/types/packs/docs.d.ts +3 -4
- package/dist/types/packs/work.d.ts +18 -2
- package/package.json +1 -1
|
@@ -33,9 +33,20 @@ export declare const textBan: (options: {
|
|
|
33
33
|
* (which is right for a file, where a hit must be able to name its line) every one of those
|
|
34
34
|
* patterns matches nothing, silently: the rule loads, counts, and cannot catch the thing it
|
|
35
35
|
* names.
|
|
36
|
+
*
|
|
37
|
+
* WITHOUT ITS HEREDOC BODIES (`elideHeredocs`), by default. A heredoc is text fed to a program,
|
|
38
|
+
* and a python script or a note that names a banned command is not a use of it: matched whole,
|
|
39
|
+
* `python3 - <<'PY'` scripts were refused for naming a recipe in a string. Only the bodies go —
|
|
40
|
+
* the newlines the patterns above span are kept — and a body a shell reads stays, because it is
|
|
41
|
+
* commands.
|
|
42
|
+
*
|
|
43
|
+
* `matchHeredocs: true` matches the whole command instead. A rule about what a command is FED —
|
|
44
|
+
* the text of a commit message given on stdin, `git commit -F - <<'EOF'` — has to see the body,
|
|
45
|
+
* and would be blind to that message without it.
|
|
36
46
|
*/
|
|
37
47
|
export declare const banCommands: (options: {
|
|
38
48
|
ban: readonly string[];
|
|
49
|
+
matchHeredocs?: boolean;
|
|
39
50
|
}) => Check;
|
|
40
51
|
/**
|
|
41
52
|
* A `banCommands` pattern for: a command that writes permanent prose, with a BACKTICK inside a
|
|
@@ -86,6 +97,24 @@ export declare const SUBSTITUTION_MESSAGE: string;
|
|
|
86
97
|
export declare const protectedPath: (options: {
|
|
87
98
|
existingOnly?: boolean;
|
|
88
99
|
}) => Check;
|
|
100
|
+
/**
|
|
101
|
+
* Only the listed categories may change a file: a write or a delete by any other actor is refused.
|
|
102
|
+
*
|
|
103
|
+
* It reads `ctx.actor` — the categories the acting session wears, recognised from what the host
|
|
104
|
+
* wrote about it, never from a claim it made — and nothing about the file. A session wearing none
|
|
105
|
+
* of `writers` is refused whatever it wrote, and one wearing none at all is refused too: "no
|
|
106
|
+
* category" is not "every category".
|
|
107
|
+
*
|
|
108
|
+
* `.for(…)` on an entry says which actors a RULE applies to; this says which actors may WRITE. Both
|
|
109
|
+
* read the same categories, and they answer different questions — a rule for a checker says what a
|
|
110
|
+
* checker may not do, this says that everybody but a builder may not write.
|
|
111
|
+
*
|
|
112
|
+
* An empty `writers` is refused at load: it would refuse every change by everyone, which is a
|
|
113
|
+
* frozen worktree, not a rule about who writes it.
|
|
114
|
+
*/
|
|
115
|
+
export declare const oneWriter: (options: {
|
|
116
|
+
writers: readonly string[];
|
|
117
|
+
}) => Check;
|
|
89
118
|
/**
|
|
90
119
|
* A file must have a required companion on disk — every `src/domain/**` needs its `.test.ts`.
|
|
91
120
|
*
|
|
@@ -241,6 +270,44 @@ export declare const changeTogether: (options: {
|
|
|
241
270
|
* aimed at a directory called HEAD.
|
|
242
271
|
*/
|
|
243
272
|
export declare const GIT_VALUE_OPTS: ReadonlySet<string>;
|
|
273
|
+
/** A heredoc's opener: its delimiter, whether `<<-` strips leading tabs, and where the opener ends. */
|
|
274
|
+
export interface HeredocOpen {
|
|
275
|
+
readonly delim: string;
|
|
276
|
+
readonly tabs: boolean;
|
|
277
|
+
readonly end: number;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* The first heredoc opener anywhere in a line, quoted context or not — the one definition of "this
|
|
281
|
+
* line carries a heredoc". A here-string (`<<<`) is stepped over whole, so its tail is not read as
|
|
282
|
+
* one.
|
|
283
|
+
*/
|
|
284
|
+
export declare function firstHeredoc(s: string): HeredocOpen | null;
|
|
285
|
+
/**
|
|
286
|
+
* Where a `$(` closes, honouring quotes, nesting and any heredoc inside it — a body is text, so an
|
|
287
|
+
* apostrophe or a `)` in it closes nothing. -1 when it never closes.
|
|
288
|
+
*/
|
|
289
|
+
export declare function closeParen(s: string, from: number): number;
|
|
290
|
+
/** Where a double-quoted run closes — a `"` inside a `$(…)` in it does not close it. -1 when it never does. */
|
|
291
|
+
export declare function dquoteEnd(s: string, from: number): number;
|
|
292
|
+
/**
|
|
293
|
+
* THE COMMAND LINE WITHOUT ITS HEREDOC BODIES — what a command ban matches unless the rule sets
|
|
294
|
+
* `matchHeredocs`.
|
|
295
|
+
*
|
|
296
|
+
* A heredoc is text fed to a program on its standard input: a python script, a file being written,
|
|
297
|
+
* a note. The words of a banned command inside it are not a use of that command, and matching
|
|
298
|
+
* them refused `python3 - <<'PY'` scripts for naming a recipe in a string. Every body is removed
|
|
299
|
+
* (its terminator line stays, so the opener still ends), whether the delimiter is quoted or not,
|
|
300
|
+
* and wherever the heredoc sits —
|
|
301
|
+
* inside a `$(…)` or a quoted argument too. EVERYTHING ELSE IS LEFT AS WRITTEN — newlines
|
|
302
|
+
* included, because the patterns that police a commit message span them.
|
|
303
|
+
*
|
|
304
|
+
* One exception keeps a body: a heredoc fed to a SHELL (`bash`, `sh`, `zsh`, `eval`, or a pipeline
|
|
305
|
+
* into one), whose body is commands, and a banned one in it will run.
|
|
306
|
+
*
|
|
307
|
+
* Best-effort, and it errs toward matching: from a word whose quote never closes, the line is
|
|
308
|
+
* returned as written, so a ban still sees everything it saw before.
|
|
309
|
+
*/
|
|
310
|
+
export declare function elideHeredocs(command: string): string;
|
|
244
311
|
/**
|
|
245
312
|
* A shell-ish tokeniser: quotes respected (so a commit message mentioning `git commit` is not a
|
|
246
313
|
* second command), operators emitted as their own tokens.
|
|
@@ -266,19 +333,6 @@ export interface GitInvocation {
|
|
|
266
333
|
* operator — so a `git` inside a quoted message or as an argument to something else is not one.
|
|
267
334
|
*/
|
|
268
335
|
export declare function gitInvocations(command: string): GitInvocation[] | null;
|
|
269
|
-
/**
|
|
270
|
-
* The body of the first heredoc in the raw command, or null.
|
|
271
|
-
*
|
|
272
|
-
* `git commit -F -` reads its message on stdin, and a QUOTED heredoc is the safe way to write one
|
|
273
|
-
* containing backticks — a form this codebase's own rules push commits toward. The argument scan
|
|
274
|
-
* cannot see it: there is no `-m` token, so a message written that way goes unjudged, and every
|
|
275
|
-
* rule that reads a commit message is inert on it.
|
|
276
|
-
*
|
|
277
|
-
* Deliberately last-resort and deliberately dumb — it runs only when no inline message was found,
|
|
278
|
-
* and reads the FIRST heredoc, because a commit command carrying two is not a shape anyone writes
|
|
279
|
-
* and guessing between them would be worse than the gap.
|
|
280
|
-
*/
|
|
281
|
-
export declare function heredocBody(command: string): string | null;
|
|
282
336
|
/**
|
|
283
337
|
* The message a `git commit` in this command line carries, or null when there is no judgeable
|
|
284
338
|
* commit in it at all. Null is the "not our business" answer and every caller passes on it.
|
|
@@ -296,7 +350,10 @@ export declare function heredocBody(command: string): string | null;
|
|
|
296
350
|
*
|
|
297
351
|
* git commit -m MSG · -mMSG · --message MSG · --message=MSG judged
|
|
298
352
|
* git commit -m SUBJECT -m BODY (repeated, any mix of forms) judged, joined as git joins them
|
|
299
|
-
* git commit -F - <<'EOF' … EOF (
|
|
353
|
+
* git commit -F - <<'EOF' … EOF (the commit reads stdin) judged, via the heredoc body
|
|
354
|
+
* python3 - <<'PY' … PY; git commit -F msg.txt NOT judged — the heredoc is
|
|
355
|
+
* another command's script, and
|
|
356
|
+
* the message is on disk
|
|
300
357
|
* git commit -F path/to/file NOT judged — the message is on
|
|
301
358
|
* disk, and reading it is a read
|
|
302
359
|
* of the world this layer does not
|
|
@@ -584,10 +641,24 @@ export interface RequireEdge {
|
|
|
584
641
|
* language, and a fence written in regexes is a fence nobody re-reads — the compiled literals of
|
|
585
642
|
* one such config were dead for four days while the guard's own status reported it healthy.
|
|
586
643
|
*/
|
|
644
|
+
/**
|
|
645
|
+
* One layer: the globs that are in it, and — optionally — the globs that are NOT.
|
|
646
|
+
*
|
|
647
|
+
* `not` exists because the shape a real architecture wants is "this folder, except these few": the
|
|
648
|
+
* marketing surface of a site is `src/pages/**` minus the handful of subtrees that are endpoints.
|
|
649
|
+
* Written as an enumeration of what IS marketing, the fence silently stops covering the next folder
|
|
650
|
+
* somebody adds — which is the failure this dialect is supposed to prevent, not cause. It compiles
|
|
651
|
+
* to dependency-cruiser's own `pathNot`, which is the same pair the `only` rule already uses.
|
|
652
|
+
*/
|
|
653
|
+
export interface Layer {
|
|
654
|
+
readonly path: readonly string[];
|
|
655
|
+
readonly not?: readonly string[];
|
|
656
|
+
}
|
|
587
657
|
export interface Dialect {
|
|
588
658
|
/** What to cruise. A GLOB, because a bare directory makes depcruise cruise zero modules. */
|
|
589
659
|
readonly scan: string;
|
|
590
|
-
|
|
660
|
+
/** Each layer, as globs — a bare list, or `{ path, not }` when it has holes in it. */
|
|
661
|
+
readonly layers: Readonly<Record<string, readonly string[] | Layer>>;
|
|
591
662
|
/** Fail-closed allowlist: a layer may reach ONLY these layers. */
|
|
592
663
|
readonly only?: Readonly<Record<string, readonly string[]>>;
|
|
593
664
|
/** Forbidden edges, each carrying the `why` its violation prints. */
|
|
@@ -635,7 +706,12 @@ export declare function entryToMatcher(entry: string): {
|
|
|
635
706
|
path?: string;
|
|
636
707
|
};
|
|
637
708
|
/** Layer names → a depcruise matcher fragment. `path` is an OR-list; builtins become a type. */
|
|
638
|
-
|
|
709
|
+
/** The globs a layer holds, whichever of the two ways it was written. */
|
|
710
|
+
export declare function layerGlobs(layer: readonly string[] | Layer | undefined): {
|
|
711
|
+
path: readonly string[];
|
|
712
|
+
not: readonly string[];
|
|
713
|
+
};
|
|
714
|
+
export declare function layersMatcher(names: readonly string[], layers: Readonly<Record<string, readonly string[] | Layer>>): Matcher;
|
|
639
715
|
/** The whole dialect → a native `{ forbidden, required, options }` config. */
|
|
640
716
|
export declare function compileDialect(rule: Dialect): NativeConfig;
|
|
641
717
|
/**
|
|
@@ -660,6 +736,25 @@ export declare function compileDialect(rule: Dialect): NativeConfig;
|
|
|
660
736
|
export declare function depcruiseCommand(dialect: Dialect): string;
|
|
661
737
|
/** The tool's JSON report → one hit per violation, each naming the fence and its `why`. */
|
|
662
738
|
export declare function depcruiseHits(result: ExecResult): string[];
|
|
739
|
+
/**
|
|
740
|
+
* Every layer entry that is a regex where a glob belongs — the fault `depcruise` refuses to load with.
|
|
741
|
+
*
|
|
742
|
+
* MEASURED, NOT IMAGINED: the first repo to convert its guard to flow brought its fence across
|
|
743
|
+
* verbatim, layers and all, from an engine whose layers WERE regexes. They compiled to
|
|
744
|
+
* `^\^src/pages/\([^/]!app/…` — a pattern no module path can match — and the fence loaded, reported
|
|
745
|
+
* armed, walked the graph and found nothing, for as long as it took somebody to plant a probe and
|
|
746
|
+
* watch the commit sail through. A rule that cannot do its job must refuse to load.
|
|
747
|
+
*/
|
|
748
|
+
export declare function nonGlobLayers(layers: Readonly<Record<string, readonly string[] | Layer>>): string[];
|
|
749
|
+
/**
|
|
750
|
+
* A layer with holes, named in an `only` allowlist — refused, because the holes would be silent.
|
|
751
|
+
*
|
|
752
|
+
* `only` is compiled by INVERTING the allowed layers: everything not in them blocks. The inversion
|
|
753
|
+
* reads the `path` globs and nothing else, so a layer's `not` would simply not be there — the
|
|
754
|
+
* allowlist would quietly be wider than the layer it names. Rather than half-apply it, this says so
|
|
755
|
+
* at load: use plain globs for a layer that an `only` names, or express the exclusion as a `forbid`.
|
|
756
|
+
*/
|
|
757
|
+
export declare function holesInAnOnlyList(opts: Dialect): string[];
|
|
663
758
|
/**
|
|
664
759
|
* The generic import-fence runner.
|
|
665
760
|
*
|
|
@@ -266,8 +266,16 @@ export declare const FLOW_DIR = ".flow";
|
|
|
266
266
|
export declare const FLOW_GITIGNORE = "# flow's own state \u2014 telemetry and session marks, never committed.\n*\n";
|
|
267
267
|
/** The log schema this build writes, stamped into every session file's first row. */
|
|
268
268
|
export declare const LOG_VERSION = 1;
|
|
269
|
-
/**
|
|
270
|
-
|
|
269
|
+
/**
|
|
270
|
+
* Every kind a log row may be. Closed — a reader that meets another word has met corruption.
|
|
271
|
+
*
|
|
272
|
+
* `read` and `write` are what went ROUND the tool rows: a file a shell command read by name, and a
|
|
273
|
+
* file a call changed that the call did not name — a heredoc, a `sed -i`, a script. A `tool` row
|
|
274
|
+
* says a call happened; these say what it did to the tree, so the coverage and lead numbers count
|
|
275
|
+
* work done through the shell as well as through Edit. `mismatch` is the host's own list of the
|
|
276
|
+
* files a command changed disagreeing with flow's diff: a fact to read, never an input to a rule.
|
|
277
|
+
*/
|
|
278
|
+
export declare const ROW_KINDS: readonly ["meta", "tool", "breadcrumb", "guardrail", "compaction", "run", "read", "write", "mismatch"];
|
|
271
279
|
export type RowKind = (typeof ROW_KINDS)[number];
|
|
272
280
|
export declare function flowDir(root: string): string;
|
|
273
281
|
/** A session id becomes a filename, so it is held to a filename's charset. */
|
package/dist/types/glob.d.ts
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
export declare function escapeRe(s: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* Is that a REGULAR EXPRESSION where this dialect wants a glob?
|
|
4
|
+
*
|
|
5
|
+
* It lives beside `escapeRe` because it is that function read backwards: these are the shapes
|
|
6
|
+
* `escapeRe` turns into literals, which is how a pattern written as a regex comes to match nothing
|
|
7
|
+
* at all while reading as a fence. Four of them — a leading `^`, a `(?` group, a `|`, a trailing `$`
|
|
8
|
+
* — and nothing broader is claimed: this is not a regex detector, it is the list of characters whose
|
|
9
|
+
* meaning is silently lost here.
|
|
10
|
+
*
|
|
11
|
+
* ANY `|` COUNTS, with no carve-out for a backslash before it. The dialect has no escape character:
|
|
12
|
+
* `\|` is a literal backslash followed by a pipe, and a path with either in it is not a path anyone
|
|
13
|
+
* has. A carve-out would only ever wave through the thing it was meant to catch.
|
|
14
|
+
*
|
|
15
|
+
* It was found the hard way — a repo's fence, brought across from an engine whose layers WERE
|
|
16
|
+
* regexes, loaded green and refused nothing for a week.
|
|
17
|
+
*/
|
|
18
|
+
export declare function notAGlob(entry: string): boolean;
|
|
2
19
|
/** One piece of a glob. The whole dialect: `**` · `*` · `?` · `{a,b}` · literal text. */
|
|
3
20
|
export type GlobToken = {
|
|
4
21
|
readonly kind: "literal";
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { guardrail, breadcrumb, type Sentence, type EntrySpec, type GuardrailSpec, type BreadcrumbSpec, type GuardrailSentence, type BreadcrumbSentence, type EntryGroup, type DisabledMark, } from "./language/domain.ts";
|
|
2
2
|
export { definePack, pack, override, defineConfig, type Pack, type PackDefinition, type EntryRef, type RefTarget, type FlowConfig, type Binding, type PackBinding, type OverrideBinding, type ConfigSentence, } from "./language/domain.ts";
|
|
3
|
-
export { defineCheck, type Check, type Ctx, type World, type Verdict, type ExecResult, type TurnAction, type Case, type CaseWorld, type Cases, } from "./language/domain.ts";
|
|
3
|
+
export { defineCheck, withFaults, faultsOf, type Check, type Ctx, type World, type Verdict, type ExecResult, type TurnAction, type Case, type CaseWorld, type Cases, } from "./language/domain.ts";
|
|
4
4
|
export { defineCategory, type Category, type Classifier, type SessionFacts } from "./language/domain.ts";
|
|
5
|
-
export { astGrep, banCommands, canonicalFiles, changeTogether, commitReason, depcruise, execPasses, jsonInvariant, protectedPath, ranSinceEdit, siblingExists, symbolsInSibling, textBan, type CanonOptions, type ChangeGroup, type Dialect, type DiffAdds, type ForbidEdge, type JsonAssert, type RequireEdge, } from "./checks/domain.ts";
|
|
5
|
+
export { astGrep, banCommands, canonicalFiles, changeTogether, commitReason, depcruise, execPasses, jsonInvariant, oneWriter, protectedPath, ranSinceEdit, siblingExists, symbolsInSibling, textBan, type CanonOptions, type ChangeGroup, type Dialect, type Layer, type DiffAdds, type ForbidEdge, type JsonAssert, type RequireEdge, } from "./checks/domain.ts";
|
|
6
6
|
export { substitutionInProse, SUBSTITUTION_MESSAGE } from "./checks/domain.ts";
|
|
7
7
|
export { commitMessage, gitDirPrefix, gitInvocations, givesReason, quoteArg, tokenizeCommand, type GitInvocation, } from "./checks/domain.ts";
|
|
8
8
|
export { spawnedAs, type SpawnRecipe } from "./engine/domain.ts";
|
|
@@ -141,6 +141,12 @@ export interface Ctx {
|
|
|
141
141
|
readonly staged?: readonly string[] | undefined;
|
|
142
142
|
/** turn-end: what the actor did this turn, in order. */
|
|
143
143
|
readonly turn?: readonly TurnAction[] | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* Every moment: the category names that match the session making this change — the categories
|
|
146
|
+
* some bound entry names, whose recognizer said yes to the host-written evidence about it. Empty
|
|
147
|
+
* when it matches none, which is not "every category".
|
|
148
|
+
*/
|
|
149
|
+
readonly actor: readonly string[];
|
|
144
150
|
exec(cmd: string): Promise<ExecResult>;
|
|
145
151
|
readonly fs: {
|
|
146
152
|
read(path: string): Promise<string>;
|
|
@@ -191,6 +197,24 @@ export type World = Pick<Ctx, "exec" | "fs" | "git">;
|
|
|
191
197
|
* would be called with `ctx` as its receiver and break any world that closes over itself.
|
|
192
198
|
*/
|
|
193
199
|
export declare function makeCtx(moment: Moment, facts: Partial<Ctx>, world: World): Ctx;
|
|
200
|
+
/**
|
|
201
|
+
* Mark a configured check as built with options it cannot work with, and say why.
|
|
202
|
+
*
|
|
203
|
+
* WHY IT IS A VALUE AND NOT A THROW: a check factory runs while the config module is evaluating, so
|
|
204
|
+
* a throw there is a module that will not import, and the reader gets one fault with a stack trace
|
|
205
|
+
* instead of every fault with its entry named. Marked instead, the load collects it beside the
|
|
206
|
+
* grammar's own refusals and the engine blocks every gated moment with the same text — which is the
|
|
207
|
+
* shape every other load failure already has.
|
|
208
|
+
*
|
|
209
|
+
* WHY IT EXISTS AT ALL: an option can be well-TYPED and still be nonsense — the class that bit here
|
|
210
|
+
* was a depcruise layer written as a regex where the dialect takes globs, which compiled to a
|
|
211
|
+
* pattern matching nothing. The fence loaded, `flow status` called it armed, and it walked no graph
|
|
212
|
+
* for as long as nobody planted a probe. A rule that cannot do its job must refuse to load, never
|
|
213
|
+
* report green.
|
|
214
|
+
*/
|
|
215
|
+
export declare function withFaults<C extends Check>(check: C, faults: readonly string[]): C;
|
|
216
|
+
/** What a configured check said is wrong with its own options. Empty for every healthy check. */
|
|
217
|
+
export declare function faultsOf(check: Check | undefined): readonly string[];
|
|
194
218
|
/**
|
|
195
219
|
* Declare a CONFIGURED check: a function that takes options and returns a check.
|
|
196
220
|
*
|
|
@@ -245,16 +269,20 @@ export type Case =
|
|
|
245
269
|
string | {
|
|
246
270
|
readonly command: string;
|
|
247
271
|
readonly world?: CaseWorld;
|
|
272
|
+
readonly actor?: readonly string[];
|
|
248
273
|
} | {
|
|
249
274
|
readonly path: string;
|
|
250
275
|
readonly content: string;
|
|
251
276
|
readonly world?: CaseWorld;
|
|
277
|
+
readonly actor?: readonly string[];
|
|
252
278
|
} | {
|
|
253
279
|
readonly staged: readonly string[];
|
|
254
280
|
readonly world?: CaseWorld;
|
|
281
|
+
readonly actor?: readonly string[];
|
|
255
282
|
} | {
|
|
256
283
|
readonly actions: readonly TurnAction[];
|
|
257
284
|
readonly world?: CaseWorld;
|
|
285
|
+
readonly actor?: readonly string[];
|
|
258
286
|
};
|
|
259
287
|
/** The cases an entry carries: what must pass it, and what must be blocked by it. */
|
|
260
288
|
export interface Cases {
|
|
@@ -520,6 +548,19 @@ export interface Settings {
|
|
|
520
548
|
* it two ways.
|
|
521
549
|
*/
|
|
522
550
|
readonly grammars?: readonly Grammar[];
|
|
551
|
+
/**
|
|
552
|
+
* Globs for the IGNORED paths the snapshot records as well. The snapshot is git's view of the
|
|
553
|
+
* tree — tracked files, and untracked ones git does not ignore — so a shell write to an ignored
|
|
554
|
+
* file is never seen unless a glob here brings it back. `.env` is the usual one.
|
|
555
|
+
*/
|
|
556
|
+
readonly snapshotInclude?: readonly string[];
|
|
557
|
+
/**
|
|
558
|
+
* What is put back when a rule refuses a write that has already landed: `"refused"` (the default)
|
|
559
|
+
* writes back only the files a rule refused, `"all"` every file that call changed. While another
|
|
560
|
+
* agent's call overlaps it, only the refused files are put back whatever this says — that call's
|
|
561
|
+
* writes can be in the same diff.
|
|
562
|
+
*/
|
|
563
|
+
readonly revert?: "refused" | "all";
|
|
523
564
|
}
|
|
524
565
|
/**
|
|
525
566
|
* One hand-built tree-sitter grammar, as `registerDynamicLanguage` wants it.
|
|
@@ -631,7 +672,7 @@ export interface Overlaid {
|
|
|
631
672
|
*/
|
|
632
673
|
export declare function overlay(base: EntrySpec, spoken: Readonly<Record<string, unknown>>, prior?: Readonly<Record<string, "pack" | "override">>): Overlaid;
|
|
633
674
|
/** The closed vocabulary of refusals. Every load failure is exactly one of these. */
|
|
634
|
-
export declare const REFUSAL_CODES: readonly ["not-a-pack", "missing-parameter", "unknown-entry", "unknown-key", "unknown-moment", "missing-mandatory", "undeclared-category", "no-cases", "duplicate-id", "dead-scope"];
|
|
675
|
+
export declare const REFUSAL_CODES: readonly ["not-a-pack", "missing-parameter", "unknown-entry", "unknown-key", "unknown-moment", "missing-mandatory", "undeclared-category", "no-cases", "duplicate-id", "dead-scope", "bad-check-options"];
|
|
635
676
|
export type RefusalCode = (typeof REFUSAL_CODES)[number];
|
|
636
677
|
/** One reason the config will not load. */
|
|
637
678
|
export interface Refusal {
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* least possible cognitive load, and the agent wants almost nothing in context. So `docs/` has
|
|
6
6
|
* exactly two doors and everything inside follows its door's rules.
|
|
7
7
|
*
|
|
8
|
-
* @setup A `docs/` folder holding exactly `user/` and `agent/`, each with its own index —
|
|
9
|
-
* `docs/user
|
|
10
|
-
*
|
|
8
|
+
* @setup A `docs/` folder holding exactly `user/` and `agent/`, each with its own index — an index
|
|
9
|
+
* file under `docs/user/` for people and `docs/agent/README.md` as a list of pointers. The
|
|
10
|
+
* guardrail below refuses anything else at the top of the folder, so a repo with a different shape
|
|
11
11
|
* either moves its pages or does not bind this pack.
|
|
12
12
|
*/
|
|
13
13
|
export interface Doors {
|
|
@@ -45,5 +45,4 @@ export declare const docs: import("../index.ts").Pack<{
|
|
|
45
45
|
* drawer, and neither audience's rules can be applied to what is in it.
|
|
46
46
|
*/
|
|
47
47
|
docsShape: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "on" | "description", "write" | "commit">;
|
|
48
|
-
noMarkdownInUserDocs: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "on" | "description", "write" | "commit">;
|
|
49
48
|
}, Doors | undefined>;
|
|
@@ -17,6 +17,20 @@ export declare const builder: import("../index.ts").Category;
|
|
|
17
17
|
* a frontmatter list somebody can widen.
|
|
18
18
|
*/
|
|
19
19
|
export declare const checker: import("../index.ts").Category;
|
|
20
|
+
/** The rungs that may be named as writers — a checker is the rung that never writes. */
|
|
21
|
+
export type Writer = "builder" | "parent";
|
|
22
|
+
/** What a repo may say about how it runs the lifecycle. Every field is optional. */
|
|
23
|
+
export interface Rungs {
|
|
24
|
+
/**
|
|
25
|
+
* The rungs allowed to change files in a worktree, turning on ONE WRITER: a write or a delete by
|
|
26
|
+
* any other actor is refused — an Edit before it lands, anything else put back after.
|
|
27
|
+
*
|
|
28
|
+
* OPTIONAL, and with no list there is no entry at all. One writer is for a worktree several
|
|
29
|
+
* agents share with one builder in it; in a repo where a helper agent of any other kind is
|
|
30
|
+
* expected to write, it would refuse that helper's every change, so it is off until a repo asks.
|
|
31
|
+
*/
|
|
32
|
+
readonly writers?: readonly Writer[];
|
|
33
|
+
}
|
|
20
34
|
/**
|
|
21
35
|
* The WORK LIFECYCLE's rungs: who is acting, and what each rung may do.
|
|
22
36
|
*
|
|
@@ -38,12 +52,14 @@ export declare const checker: import("../index.ts").Category;
|
|
|
38
52
|
* so in a repo that does not run the lifecycle they are five rules that can never fire.
|
|
39
53
|
* @adopt Bind it only in a repo whose tasks are actually run through the lifecycle. The three rung
|
|
40
54
|
* rules are scoped to categories this pack defines, so they judge nobody until a session is
|
|
41
|
-
* classified as a builder or a checker — a human at a keyboard is neither.
|
|
55
|
+
* classified as a builder or a checker — a human at a keyboard is neither. Name `writers` to let
|
|
56
|
+
* only those rungs change files in the worktree.
|
|
42
57
|
*/
|
|
43
58
|
export declare const work: import("../index.ts").Pack<{
|
|
59
|
+
builderWrites?: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "description", "write" | "delete">;
|
|
44
60
|
planIsTheParents: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "for" | "description", "command">;
|
|
45
61
|
checkersDoNotWrite: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "for" | "description", "write">;
|
|
46
62
|
ticksAreTheChilds: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "for" | "description", "command">;
|
|
47
63
|
noAgentInboxItems: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "description", "command">;
|
|
48
64
|
noShellSubstitutionInProse: import("../index.ts").GuardrailSentence<"at" | "check" | "message" | "test" | "description", "command">;
|
|
49
|
-
}, undefined>;
|
|
65
|
+
}, Rungs | undefined>;
|