@llm4ts/flow 2.30.0 → 2.31.0

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.
Files changed (74) hide show
  1. package/dist/AutonomyContract.d.ts +12 -0
  2. package/dist/AutonomyContract.d.ts.map +1 -0
  3. package/dist/AutonomyContract.js +51 -0
  4. package/dist/AutonomyContract.js.map +1 -0
  5. package/dist/CarriedNotes.d.ts +10 -0
  6. package/dist/CarriedNotes.d.ts.map +1 -1
  7. package/dist/CarriedNotes.js +27 -2
  8. package/dist/CarriedNotes.js.map +1 -1
  9. package/dist/Evidence.d.ts +12 -0
  10. package/dist/Evidence.d.ts.map +1 -0
  11. package/dist/Evidence.js +30 -0
  12. package/dist/Evidence.js.map +1 -0
  13. package/dist/Flow.d.ts +35 -3
  14. package/dist/Flow.d.ts.map +1 -1
  15. package/dist/Flow.js +58 -4
  16. package/dist/Flow.js.map +1 -1
  17. package/dist/FlowEvents.d.ts +14 -1
  18. package/dist/FlowEvents.d.ts.map +1 -1
  19. package/dist/FlowEvents.js +13 -0
  20. package/dist/FlowEvents.js.map +1 -1
  21. package/dist/GateTriage.d.ts +81 -0
  22. package/dist/GateTriage.d.ts.map +1 -0
  23. package/dist/GateTriage.js +161 -0
  24. package/dist/GateTriage.js.map +1 -0
  25. package/dist/Gates.d.ts +35 -0
  26. package/dist/Gates.d.ts.map +1 -0
  27. package/dist/Gates.js +63 -0
  28. package/dist/Gates.js.map +1 -0
  29. package/dist/OracleGuard.d.ts +53 -0
  30. package/dist/OracleGuard.d.ts.map +1 -0
  31. package/dist/OracleGuard.js +165 -0
  32. package/dist/OracleGuard.js.map +1 -0
  33. package/dist/Pack.d.ts +7 -0
  34. package/dist/Pack.d.ts.map +1 -1
  35. package/dist/Pack.js +9 -0
  36. package/dist/Pack.js.map +1 -1
  37. package/dist/Retro.d.ts.map +1 -1
  38. package/dist/Retro.js +5 -0
  39. package/dist/Retro.js.map +1 -1
  40. package/dist/Review.d.ts +68 -2
  41. package/dist/Review.d.ts.map +1 -1
  42. package/dist/Review.js +158 -27
  43. package/dist/Review.js.map +1 -1
  44. package/dist/Roster.d.ts +2 -0
  45. package/dist/Roster.d.ts.map +1 -1
  46. package/dist/Roster.js +3 -1
  47. package/dist/Roster.js.map +1 -1
  48. package/dist/RosterSeats.d.ts +2 -0
  49. package/dist/RosterSeats.d.ts.map +1 -1
  50. package/dist/RosterSeats.js.map +1 -1
  51. package/dist/Stories.d.ts +36 -2
  52. package/dist/Stories.d.ts.map +1 -1
  53. package/dist/Stories.js +159 -12
  54. package/dist/Stories.js.map +1 -1
  55. package/dist/StoryPlan.d.ts +6 -0
  56. package/dist/StoryPlan.d.ts.map +1 -1
  57. package/dist/StoryPlan.js +9 -2
  58. package/dist/StoryPlan.js.map +1 -1
  59. package/package.json +7 -2
  60. package/src/AutonomyContract.ts +61 -0
  61. package/src/CarriedNotes.ts +37 -2
  62. package/src/Evidence.ts +43 -0
  63. package/src/Flow.ts +109 -3
  64. package/src/FlowEvents.ts +13 -0
  65. package/src/GateTriage.ts +250 -0
  66. package/src/Gates.ts +104 -0
  67. package/src/OracleGuard.ts +205 -0
  68. package/src/Pack.ts +16 -0
  69. package/src/Retro.ts +7 -0
  70. package/src/Review.ts +261 -34
  71. package/src/Roster.ts +3 -1
  72. package/src/RosterSeats.ts +2 -0
  73. package/src/Stories.ts +289 -16
  74. package/src/StoryPlan.ts +11 -1
@@ -0,0 +1,81 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Schema from "effect/Schema";
3
+ import type { PersistenceError } from "./FlowError.ts";
4
+ import type { PlainFileStoreShape } from "./Persistence.ts";
5
+ import { ReviewIssue, ReviewResult } from "./Review.ts";
6
+ export declare const GateClass: Schema.Literals<readonly ["red", "hang", "crash"]>;
7
+ export type GateClass = typeof GateClass.Type;
8
+ export declare const FailureOrigin: Schema.Literals<readonly ["new", "base", "flaky"]>;
9
+ export type FailureOrigin = typeof FailureOrigin.Type;
10
+ declare const GateBaseline_base: Schema.Class<GateBaseline, Schema.Struct<{
11
+ readonly baseCommit: Schema.String;
12
+ readonly appDir: Schema.String;
13
+ /** Each gate command as configured, joined with one space. */
14
+ readonly commands: Schema.$Array<Schema.String>;
15
+ readonly failingLines: Schema.$Array<Schema.String>;
16
+ /** Tests passing on the base, when the test gate's output said (the oracle guard compares). */
17
+ readonly passedCount: Schema.optionalKey<Schema.Int>;
18
+ readonly recordedAt: Schema.Number;
19
+ }>, {}>;
20
+ export declare class GateBaseline extends GateBaseline_base {
21
+ }
22
+ /**
23
+ * The lines of a gate's output a change can be blamed for, made comparable
24
+ * across runs and worktrees: colours, timings, timestamps and the given root
25
+ * prefixes removed; stack frames, summaries and blank lines dropped; only
26
+ * lines carrying a failure marker kept, each once. A heuristic by design:
27
+ * per-tool parsers are kit material (a pack `diagnostics:` command, later).
28
+ */
29
+ export declare const normalizeGateOutput: (text: string, roots: ReadonlyArray<string>) => ReadonlyArray<string>;
30
+ /** The title prefix `lintCommand` gives every gate issue; nothing else is a gate. */
31
+ export declare const gateIssuePrefix = "lint failed: ";
32
+ export declare const isGateIssue: (issue: ReviewIssue) => boolean;
33
+ /** Every gate issue's normalized failing lines, in order, each once. */
34
+ export declare const failingLinesOf: (result: ReviewResult, roots: ReadonlyArray<string>) => ReadonlyArray<string>;
35
+ export interface GateTriage {
36
+ /** The lint result with only the failures the change caused; clean when it caused none. */
37
+ readonly blocking: ReviewResult;
38
+ readonly newLines: ReadonlyArray<string>;
39
+ /** Failing lines already red on the base: listed, never charged. */
40
+ readonly inherited: ReadonlyArray<string>;
41
+ }
42
+ /**
43
+ * Splits a lint result against the baseline. A gate issue whose every
44
+ * failing line is on the baseline is dropped (inherited); one with new lines
45
+ * is kept with `origin: "new"` and its description reduced to those lines,
46
+ * so the fix prompt names only what the change broke. A gate issue with no
47
+ * recognizable failing line at all (a hang, a crash, an unparsed output) is
48
+ * kept whole. Non-gate issues (the perimeter, the oracle guard) pass through.
49
+ * Without a baseline the result is returned as is.
50
+ */
51
+ export declare const triageGates: (result: ReviewResult, baseline: GateBaseline | undefined, roots: ReadonlyArray<string>) => GateTriage;
52
+ export declare const baselineKey: (parts: {
53
+ readonly baseCommit: string;
54
+ readonly appDir: string;
55
+ readonly commands: ReadonlyArray<ReadonlyArray<string>>;
56
+ }) => string;
57
+ /** The one file a run keeps its baselines in. */
58
+ export declare const baselinesPath: (stateDir: string) => string;
59
+ export declare const readBaseline: (files: PlainFileStoreShape, stateDir: string, key: string) => Effect.Effect<GateBaseline | undefined, PersistenceError>;
60
+ export interface EnsureBaselineArgs<E> {
61
+ readonly files: PlainFileStoreShape;
62
+ readonly stateDir: string;
63
+ /** The commit the change starts from. */
64
+ readonly commit: string;
65
+ readonly appDir: string;
66
+ readonly commands: ReadonlyArray<ReadonlyArray<string>>;
67
+ /** Runs the gates on that commit; called only when no baseline is stored. */
68
+ readonly run: Effect.Effect<ReviewResult, E>;
69
+ /** Root prefixes stripped from gate output (the work dir, the app dir). */
70
+ readonly roots: ReadonlyArray<string>;
71
+ readonly now: Effect.Effect<number>;
72
+ }
73
+ /**
74
+ * The baseline for a commit: the stored one, or a fresh one recorded from
75
+ * `run`. Lazy on purpose, so a second change on an unchanged commit costs
76
+ * no gate run.
77
+ */
78
+ export declare const ensureBaseline: <E>(args: EnsureBaselineArgs<E>) => Effect.Effect<GateBaseline, E | PersistenceError>;
79
+ export declare const writeBaseline: (files: PlainFileStoreShape, stateDir: string, key: string, baseline: GateBaseline) => Effect.Effect<void, PersistenceError>;
80
+ export {};
81
+ //# sourceMappingURL=GateTriage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GateTriage.d.ts","sourceRoot":"","sources":["../src/GateTriage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGvD,eAAO,MAAM,SAAS,oDAA4C,CAAA;AAClE,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C,eAAO,MAAM,aAAa,oDAA4C,CAAA;AACtE,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAA;;;;IAKnD,8DAA8D;;;IAG9D,+FAA+F;;;;AANjG,qBAAa,YAAa,SAAQ,iBAShC;CAAG;AAkBL;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,MAAM,MAAM,EACZ,OAAO,aAAa,CAAC,MAAM,CAAC,KAC3B,aAAa,CAAC,MAAM,CAuBtB,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,eAAe,kBAAkB,CAAA;AAE9C,eAAO,MAAM,WAAW,GAAI,OAAO,WAAW,KAAG,OAAkD,CAAA;AAEnG,wEAAwE;AACxE,eAAO,MAAM,cAAc,GACzB,QAAQ,YAAY,EACpB,OAAO,aAAa,CAAC,MAAM,CAAC,KAC3B,aAAa,CAAC,MAAM,CAOpB,CAAA;AAEH,MAAM,WAAW,UAAU;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACxC,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAC1C;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,YAAY,EACpB,UAAU,YAAY,GAAG,SAAS,EAClC,OAAO,aAAa,CAAC,MAAM,CAAC,KAC3B,UAoCF,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,OAAO;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;CACxD,KAAG,MAKa,CAAA;AAEjB,iDAAiD;AACjD,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,KAAG,MACQ,CAAA;AAiBzD,eAAO,MAAM,YAAY,GACvB,OAAO,mBAAmB,EAC1B,UAAU,MAAM,EAChB,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,CAAC,YAAY,GAAG,SAAS,EAAE,gBAAgB,CACa,CAAA;AAExE,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IACvD,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;CACpC;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,EAC9B,MAAM,kBAAkB,CAAC,CAAC,CAAC,KAC1B,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,GAAG,gBAAgB,CAsB/C,CAAA;AAEJ,eAAO,MAAM,aAAa,GACxB,OAAO,mBAAmB,EAC1B,UAAU,MAAM,EAChB,KAAK,MAAM,EACX,UAAU,YAAY,KACrB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAKtC,CAAA"}
@@ -0,0 +1,161 @@
1
+ // Gates with a memory (ADR 0027): what the target's gates said on the code a
2
+ // change started from, and which failing lines the change can be charged
3
+ // with. Pure helpers and a small store; the seams are lintCommand and
4
+ // reviewAndFixLoop (Review.ts), implementPlanFlow (Flow.ts) and the story
5
+ // executor (Stories.ts). Gates.ts re-exports this module beside gatesIn.
6
+ import * as Effect from "effect/Effect";
7
+ import * as Schema from "effect/Schema";
8
+ import { ReviewIssue, ReviewResult } from "./Review.js";
9
+ import { fingerprintOf } from "./ReviewCache.js";
10
+ export const GateClass = Schema.Literals(["red", "hang", "crash"]);
11
+ export const FailureOrigin = Schema.Literals(["new", "base", "flaky"]);
12
+ export class GateBaseline extends Schema.Class("GateBaseline")({
13
+ baseCommit: Schema.String,
14
+ appDir: Schema.String,
15
+ /** Each gate command as configured, joined with one space. */
16
+ commands: Schema.Array(Schema.String),
17
+ failingLines: Schema.Array(Schema.String),
18
+ /** Tests passing on the base, when the test gate's output said (the oracle guard compares). */
19
+ passedCount: Schema.optionalKey(Schema.Int),
20
+ recordedAt: Schema.Number
21
+ }) {
22
+ }
23
+ /** Every baseline a run recorded, by `baselineKey`; one file, deleted on land. */
24
+ const Baselines = Schema.Record(Schema.String, GateBaseline);
25
+ const BaselinesJson = Schema.fromJsonString(Baselines);
26
+ const decodeBaselines = Schema.decodeUnknownEffect(BaselinesJson);
27
+ const encodeBaselines = Schema.encodeSync(BaselinesJson);
28
+ // Built from the escape code point so the pattern holds no control character literal.
29
+ const ansi = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "gu");
30
+ const duration = /\b\d+(?:\.\d+)?\s?(?:ms|s|m)\b/gu;
31
+ const isoTimestamp = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?/gu;
32
+ const stackFrame = /^\s*at\s/u;
33
+ const summaryLine = /^\s*(?:Test Files|Tests|Duration|Start at|Snapshots|Found \d+ errors?|\d+ (?:passing|failing|pending))\b/u;
34
+ const failureMarker = /FAIL|✗|×|✘|✖|❯|error|Error|AssertionError|Expected|Received|expected|TS\d{4}/u;
35
+ /**
36
+ * The lines of a gate's output a change can be blamed for, made comparable
37
+ * across runs and worktrees: colours, timings, timestamps and the given root
38
+ * prefixes removed; stack frames, summaries and blank lines dropped; only
39
+ * lines carrying a failure marker kept, each once. A heuristic by design:
40
+ * per-tool parsers are kit material (a pack `diagnostics:` command, later).
41
+ */
42
+ export const normalizeGateOutput = (text, roots) => {
43
+ const prefixes = roots.filter((root) => root.length > 0).map((root) => root.replace(/\/+$/u, ""));
44
+ const seen = new Set();
45
+ const out = [];
46
+ for (const raw of text.split(/\r?\n/u)) {
47
+ let line = raw.replace(ansi, "");
48
+ for (const prefix of prefixes) {
49
+ line = line.replaceAll(`${prefix}/`, "");
50
+ }
51
+ line = line.replace(isoTimestamp, "<ts>").replace(duration, "<t>").trim();
52
+ if (line.length === 0 || stackFrame.test(line) || summaryLine.test(line)) {
53
+ continue;
54
+ }
55
+ if (!failureMarker.test(line)) {
56
+ continue;
57
+ }
58
+ line = line.replace(/\s+/gu, " ");
59
+ if (!seen.has(line)) {
60
+ seen.add(line);
61
+ out.push(line);
62
+ }
63
+ }
64
+ return out;
65
+ };
66
+ /** The title prefix `lintCommand` gives every gate issue; nothing else is a gate. */
67
+ export const gateIssuePrefix = "lint failed: ";
68
+ export const isGateIssue = (issue) => issue.title.startsWith(gateIssuePrefix);
69
+ /** Every gate issue's normalized failing lines, in order, each once. */
70
+ export const failingLinesOf = (result, roots) => Array.from(new Set(result.issues
71
+ .filter(isGateIssue)
72
+ .flatMap((issue) => normalizeGateOutput(issue.description, roots))));
73
+ /**
74
+ * Splits a lint result against the baseline. A gate issue whose every
75
+ * failing line is on the baseline is dropped (inherited); one with new lines
76
+ * is kept with `origin: "new"` and its description reduced to those lines,
77
+ * so the fix prompt names only what the change broke. A gate issue with no
78
+ * recognizable failing line at all (a hang, a crash, an unparsed output) is
79
+ * kept whole. Non-gate issues (the perimeter, the oracle guard) pass through.
80
+ * Without a baseline the result is returned as is.
81
+ */
82
+ export const triageGates = (result, baseline, roots) => {
83
+ if (baseline === undefined || result.isClean) {
84
+ return { blocking: result, newLines: [], inherited: [] };
85
+ }
86
+ const known = new Set(baseline.failingLines);
87
+ const newLines = [];
88
+ const inherited = [];
89
+ const issues = [];
90
+ for (const issue of result.issues) {
91
+ if (!isGateIssue(issue)) {
92
+ issues.push(issue);
93
+ continue;
94
+ }
95
+ const lines = normalizeGateOutput(issue.description, roots);
96
+ const fresh = lines.filter((line) => !known.has(line));
97
+ inherited.push(...lines.filter((line) => known.has(line)));
98
+ if (lines.length > 0 && fresh.length === 0) {
99
+ continue;
100
+ }
101
+ newLines.push(...fresh);
102
+ issues.push(ReviewIssue.make({
103
+ ...issue,
104
+ origin: "new",
105
+ description: fresh.length > 0 ? fresh.join("\n") : issue.description
106
+ }));
107
+ }
108
+ return {
109
+ blocking: ReviewResult.make({
110
+ issues,
111
+ summary: issues.length === 0 ? "lint passed (inherited failures only)" : result.summary
112
+ }),
113
+ newLines: Array.from(new Set(newLines)),
114
+ inherited: Array.from(new Set(inherited))
115
+ };
116
+ };
117
+ export const baselineKey = (parts) => fingerprintOf([
118
+ parts.baseCommit,
119
+ parts.appDir,
120
+ ...parts.commands.map((command) => command.join(" "))
121
+ ]).slice(0, 16);
122
+ /** The one file a run keeps its baselines in. */
123
+ export const baselinesPath = (stateDir) => `${stateDir.replace(/\/+$/u, "")}/gates/baselines.json`;
124
+ const readAll = (files, path) => files.read(path).pipe(Effect.flatMap((text) => text === undefined
125
+ ? Effect.succeed({})
126
+ : decodeBaselines(text).pipe(
127
+ // An unreadable file is no baseline: the caller records a fresh one.
128
+ Effect.catch(() => Effect.succeed({})))));
129
+ export const readBaseline = (files, stateDir, key) => Effect.map(readAll(files, baselinesPath(stateDir)), (all) => all[key]);
130
+ /**
131
+ * The baseline for a commit: the stored one, or a fresh one recorded from
132
+ * `run`. Lazy on purpose, so a second change on an unchanged commit costs
133
+ * no gate run.
134
+ */
135
+ export const ensureBaseline = (args) => Effect.gen(function* () {
136
+ const key = baselineKey({
137
+ baseCommit: args.commit,
138
+ appDir: args.appDir,
139
+ commands: args.commands
140
+ });
141
+ const stored = yield* readBaseline(args.files, args.stateDir, key);
142
+ if (stored !== undefined) {
143
+ return stored;
144
+ }
145
+ const result = yield* args.run;
146
+ const baseline = GateBaseline.make({
147
+ baseCommit: args.commit,
148
+ appDir: args.appDir,
149
+ commands: args.commands.map((command) => command.join(" ")),
150
+ failingLines: failingLinesOf(result, args.roots),
151
+ ...(result.passed === undefined ? {} : { passedCount: result.passed }),
152
+ recordedAt: yield* args.now
153
+ });
154
+ yield* writeBaseline(args.files, args.stateDir, key, baseline);
155
+ return baseline;
156
+ });
157
+ export const writeBaseline = (files, stateDir, key, baseline) => {
158
+ const path = baselinesPath(stateDir);
159
+ return Effect.flatMap(readAll(files, path), (all) => files.writeAtomic(path, encodeBaselines({ ...all, [key]: baseline })));
160
+ };
161
+ //# sourceMappingURL=GateTriage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GateTriage.js","sourceRoot":"","sources":["../src/GateTriage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type * as Duration from "effect/Duration";
2
+ import * as Effect from "effect/Effect";
3
+ import type { ProcessExecutorShape } from "@llm4ts/core/ProcessExecutor";
4
+ import type { FlowError } from "./FlowError.ts";
5
+ import type { FlowEventsShape } from "./FlowEvents.ts";
6
+ import type { PlainFileStoreShape } from "./Persistence.ts";
7
+ import { type ReviewResult } from "./Review.ts";
8
+ export * from "./GateTriage.ts";
9
+ export interface GateLogDir {
10
+ readonly files: PlainFileStoreShape;
11
+ readonly dir: string;
12
+ }
13
+ export interface GateRunOptions {
14
+ readonly timeout?: Duration.Duration;
15
+ /** Where this runner's logs go unless a call names its own; `undefined` writes none. */
16
+ readonly logDir?: GateLogDir;
17
+ }
18
+ /** `<index>-<command slug>.log`: one file per gate command, overwritten each run. */
19
+ export declare const gateLogName: (index: number, command: ReadonlyArray<string>) => string;
20
+ /** Runs the gates in a directory, stopping at the first red one (later output would be noise). */
21
+ export declare const gatesIn: (process: ProcessExecutorShape, events: FlowEventsShape, commands: ReadonlyArray<ReadonlyArray<string>>, options?: GateRunOptions) => (workDir: string, laneEvents?: FlowEventsShape, log?: GateLogDir) => Effect.Effect<ReviewResult, FlowError>;
22
+ /** A landed epic keeps why a gate was red, not the target's whole test output. */
23
+ export declare const compactGateLog: (text: string, roots: ReadonlyArray<string>) => string;
24
+ /** The gate log directory of one story under a run's state folder. */
25
+ export declare const storyGateLogDir: (stateDir: string, storyId: string) => string;
26
+ /**
27
+ * What `--land` keeps of the gates: no baselines (reproducible), and each
28
+ * story's gate logs reduced to their failing lines. Logs are enumerated from
29
+ * the story ids and the gate commands, so no listing is needed.
30
+ */
31
+ export declare const compactGateArtifacts: (files: PlainFileStoreShape, stateDir: string, storyIds: readonly string[], commands: readonly (readonly string[])[]) => Effect.Effect<{
32
+ readonly baselines: number;
33
+ readonly logs: number;
34
+ }, import("./FlowError.ts").PersistenceError | import("./FlowError.ts").PlanParseError | import("./FlowError.ts").UnsupportedSchemaVersion | import("./FlowError.ts").WorkspacePathError | import("./FlowError.ts").WorkspaceLimitError | import("./FlowError.ts").WorkspaceIoError | import("./FlowError.ts").FlowAborted | import("./FlowError.ts").ProcessError | import("./FlowError.ts").FlowLlmError | import("./FlowError.ts").FlowCapabilityDenied | import("./FlowError.ts").ColumnNotFound | import("./FlowError.ts").BudgetExceeded | import("./FlowError.ts").StoryPlanInvalid | import("./FlowError.ts").PerimeterViolation | import("./FlowError.ts").MissingDependency | import("./FlowError.ts").MergeConflict | import("./FlowError.ts").EpicCheckoutDirty | import("./FlowError.ts").RosterInvalid | import("./FlowError.ts").EpicIncomplete | import("./FlowError.ts").LandingFailed | import("./FlowError.ts").RefineRefused | import("./FlowError.ts").RosterExhausted | import("./FlowError.ts").StoryFailed | import("./FlowError.ts").DecisionsInvalid | import("./FlowError.ts").OpenPointsPending | import("./FlowError.ts").ExtractPackMissing | import("./FlowError.ts").EpicBriefInvalid | import("./FlowError.ts").EpicBriefNotApproved | import("./FlowError.ts").ContractConflict, never>;
35
+ //# sourceMappingURL=Gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Gates.d.ts","sourceRoot":"","sources":["../src/Gates.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAmC,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAEhF,cAAc,iBAAiB,CAAA;AAE/B,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAA;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IACpC,wFAAwF;IACxF,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAC7B;AAED,qFAAqF;AACrF,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,EAAE,SAAS,aAAa,CAAC,MAAM,CAAC,KAAG,MAKpD,CAAA;AAExB,kGAAkG;AAClG,eAAO,MAAM,OAAO,GAEhB,SAAS,oBAAoB,EAC7B,QAAQ,eAAe,EACvB,UAAU,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EAC9C,UAAS,cAAmB,MAG5B,SAAS,MAAM,EACf,aAAa,eAAe,EAC5B,MAAM,UAAU,KACf,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAiBpC,CAAA;AAEN,kFAAkF;AAClF,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,OAAO,aAAa,CAAC,MAAM,CAAC,KAAG,MAC/B,CAAA;AAE7C,sEAAsE;AACtE,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,EAAE,SAAS,MAAM,KAAG,MACvB,CAAA;AAE7C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;wBAKS,MAAM;mBAAiB,MAAM;yvCAmBrE,CAAA"}
package/dist/Gates.js ADDED
@@ -0,0 +1,63 @@
1
+ // The target's gates as a module (ADR 0027): run them in a directory with a
2
+ // timeout and a log per gate, remember what they said on a base, and keep
3
+ // only what matters when an epic lands. The pure half lives in
4
+ // GateTriage.ts and is re-exported here.
5
+ import { join } from "node:path";
6
+ import * as Effect from "effect/Effect";
7
+ import { baselinesPath, normalizeGateOutput } from "./GateTriage.js";
8
+ import { lintCommand, mergeReviewResults } from "./Review.js";
9
+ export * from "./GateTriage.js";
10
+ /** `<index>-<command slug>.log`: one file per gate command, overwritten each run. */
11
+ export const gateLogName = (index, command) => `${index}-${command
12
+ .join(" ")
13
+ .replace(/[^a-z0-9]+/giu, "-")
14
+ .replace(/^-|-$/gu, "")
15
+ .toLowerCase()}.log`;
16
+ /** Runs the gates in a directory, stopping at the first red one (later output would be noise). */
17
+ export const gatesIn = (process, events, commands, options = {}) => (workDir, laneEvents, log) => Effect.gen(function* () {
18
+ const sink = log ?? options.logDir;
19
+ const results = [];
20
+ for (const [index, command] of commands.entries()) {
21
+ const result = yield* lintCommand(process, laneEvents ?? events, command, workDir, {
22
+ ...(options.timeout === undefined ? {} : { timeout: options.timeout }),
23
+ ...(sink === undefined
24
+ ? {}
25
+ : { log: { files: sink.files, path: join(sink.dir, gateLogName(index, command)) } })
26
+ });
27
+ results.push(result);
28
+ if (!result.isClean) {
29
+ break;
30
+ }
31
+ }
32
+ return mergeReviewResults(results);
33
+ });
34
+ /** A landed epic keeps why a gate was red, not the target's whole test output. */
35
+ export const compactGateLog = (text, roots) => normalizeGateOutput(text, roots).join("\n");
36
+ /** The gate log directory of one story under a run's state folder. */
37
+ export const storyGateLogDir = (stateDir, storyId) => join(stateDir, "stories", storyId, "gates");
38
+ /**
39
+ * What `--land` keeps of the gates: no baselines (reproducible), and each
40
+ * story's gate logs reduced to their failing lines. Logs are enumerated from
41
+ * the story ids and the gate commands, so no listing is needed.
42
+ */
43
+ export const compactGateArtifacts = Effect.fn("@llm4ts/flow/Gates.compactArtifacts")(function* (files, stateDir, storyIds, commands) {
44
+ const path = baselinesPath(stateDir);
45
+ const hadBaselines = (yield* files.read(path)) !== undefined;
46
+ if (hadBaselines) {
47
+ yield* files.remove(path);
48
+ }
49
+ let logs = 0;
50
+ for (const storyId of storyIds) {
51
+ for (const [index, command] of commands.entries()) {
52
+ const logPath = join(storyGateLogDir(stateDir, storyId), gateLogName(index, command));
53
+ const text = yield* files.read(logPath);
54
+ if (text === undefined) {
55
+ continue;
56
+ }
57
+ yield* files.writeAtomic(logPath, compactGateLog(text, []));
58
+ logs += 1;
59
+ }
60
+ }
61
+ return { baselines: hadBaselines ? 1 : 0, logs };
62
+ });
63
+ //# sourceMappingURL=Gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Gates.js","sourceRoot":"","sources":["../src/Gates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import * as Schema from "effect/Schema";
2
+ import { ReviewIssue } from "./Review.ts";
3
+ declare const OracleRules_base: Schema.Class<OracleRules, Schema.Struct<{
4
+ /** Regex source: a path matching it is a test file. */
5
+ readonly testFiles: Schema.String;
6
+ /** Substrings whose appearance on an added line marks a skipped or focused test. */
7
+ readonly markers: Schema.$Array<Schema.String>;
8
+ }>, {}>;
9
+ export declare class OracleRules extends OracleRules_base {
10
+ }
11
+ export declare const defaultOracleRules: OracleRules;
12
+ /** The parsed body of a pack's `## Oracle` section: `- tests: <regex>` and `- markers: a, b`. */
13
+ export declare const oracleRulesFrom: (fields: {
14
+ readonly tests?: string;
15
+ readonly markers?: ReadonlyArray<string>;
16
+ }) => OracleRules;
17
+ export interface AddedLine {
18
+ readonly file: string;
19
+ readonly line: number;
20
+ readonly text: string;
21
+ }
22
+ export interface DiffShape {
23
+ /** Files the diff deletes outright. */
24
+ readonly deleted: ReadonlyArray<string>;
25
+ /** Lines the diff adds, with the path and the new line number. */
26
+ readonly added: ReadonlyArray<AddedLine>;
27
+ }
28
+ /** The deletions and added lines of a unified diff; pure, tolerant of noise between files. */
29
+ export declare const parseUnifiedDiff: (diff: string) => DiffShape;
30
+ /**
31
+ * The passed-test count in a test runner's output, when a summary line the
32
+ * guard knows is present (Vitest, Jest, pytest, cargo test, mocha, JUnit
33
+ * via Maven/Gradle); `undefined` otherwise, which the guard reports as an
34
+ * Info rather than a verdict.
35
+ */
36
+ export declare const passedCountIn: (output: string) => number | undefined;
37
+ export interface OracleCounts {
38
+ /** Tests passing on the base, from its baseline; `undefined` when unknown. */
39
+ readonly base: number | undefined;
40
+ /** Tests passing on the change, from its test gate; `undefined` when unknown. */
41
+ readonly current: number | undefined;
42
+ }
43
+ export declare const oracleIssuePrefix = "oracle: ";
44
+ /**
45
+ * The guard's verdict on a change: one Critical per deleted test file, one
46
+ * per added marker (with `file:line`), one for a passed-count drop; empty
47
+ * when `declared` (the plan entry says tests may change). Counts are judged
48
+ * only when both are known; a caller reports the unknown case as an Info.
49
+ */
50
+ export declare const checkOracle: (diff: DiffShape, counts: OracleCounts | undefined, rules: OracleRules, declared: boolean) => ReadonlyArray<ReviewIssue>;
51
+ export declare const isOracleIssue: (issue: ReviewIssue) => boolean;
52
+ export {};
53
+ //# sourceMappingURL=OracleGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OracleGuard.d.ts","sourceRoot":"","sources":["../src/OracleGuard.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;;IAGvC,uDAAuD;;IAEvD,oFAAoF;;;AAHtF,qBAAa,WAAY,SAAQ,gBAK/B;CAAG;AAEL,eAAO,MAAM,kBAAkB,aAgB7B,CAAA;AAEF,iGAAiG;AACjG,eAAO,MAAM,eAAe,GAAI,QAAQ;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACzC,KAAG,WAIA,CAAA;AAEJ,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,CAAA;CACzC;AAKD,8FAA8F;AAC9F,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,SAsC/C,CAAA;AAUD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,MAAM,GAAG,SAsBvD,CAAA;AAED,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC;AAED,eAAO,MAAM,iBAAiB,aAAa,CAAA;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,SAAS,EACf,QAAQ,YAAY,GAAG,SAAS,EAChC,OAAO,WAAW,EAClB,UAAU,OAAO,KAChB,aAAa,CAAC,WAAW,CA4C3B,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,OAAO,WAAW,KAAG,OACR,CAAA"}
@@ -0,0 +1,165 @@
1
+ // The oracle guard (ADR 0027, decision 4): a change may not delete a test
2
+ // file, add a skip or focus marker, or lower the passed-test count unless
3
+ // its plan entry says it may. Deterministic, from the diff and the gate
4
+ // output; a violation is a gate failure the fix round can undo.
5
+ import * as Schema from "effect/Schema";
6
+ import { ReviewIssue } from "./Review.js";
7
+ export class OracleRules extends Schema.Class("OracleRules")({
8
+ /** Regex source: a path matching it is a test file. */
9
+ testFiles: Schema.String,
10
+ /** Substrings whose appearance on an added line marks a skipped or focused test. */
11
+ markers: Schema.Array(Schema.String)
12
+ }) {
13
+ }
14
+ export const defaultOracleRules = OracleRules.make({
15
+ testFiles: "(?:^|/)(?:__tests__|tests?|spec|src/test)/|\\.(?:test|spec)\\.[cm]?[jt]sx?$|_test\\.(?:go|py|rs)$|Tests?\\.(?:java|kt|scala|cs)$|^tests?_.*\\.py$",
16
+ markers: [
17
+ ".skip(",
18
+ ".only(",
19
+ "xit(",
20
+ "xdescribe(",
21
+ "xtest(",
22
+ "test.todo(",
23
+ "it.todo(",
24
+ "@Ignore",
25
+ "@Disabled",
26
+ "@pytest.mark.skip",
27
+ "#[ignore]"
28
+ ]
29
+ });
30
+ /** The parsed body of a pack's `## Oracle` section: `- tests: <regex>` and `- markers: a, b`. */
31
+ export const oracleRulesFrom = (fields) => OracleRules.make({
32
+ testFiles: fields.tests ?? defaultOracleRules.testFiles,
33
+ markers: [...defaultOracleRules.markers, ...(fields.markers ?? [])]
34
+ });
35
+ const fileHeader = /^diff --git a\/(.+?) b\/(.+)$/u;
36
+ const hunkHeader = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/u;
37
+ /** The deletions and added lines of a unified diff; pure, tolerant of noise between files. */
38
+ export const parseUnifiedDiff = (diff) => {
39
+ const deleted = [];
40
+ const added = [];
41
+ let file;
42
+ let line = 0;
43
+ let inHunk = false;
44
+ for (const raw of diff.split(/\r?\n/u)) {
45
+ const header = fileHeader.exec(raw);
46
+ if (header !== null) {
47
+ file = header[2];
48
+ inHunk = false;
49
+ continue;
50
+ }
51
+ if (file === undefined)
52
+ continue;
53
+ if (raw.startsWith("deleted file mode")) {
54
+ deleted.push(file);
55
+ continue;
56
+ }
57
+ const hunk = hunkHeader.exec(raw);
58
+ if (hunk !== null) {
59
+ line = Number.parseInt(hunk[1] ?? "0", 10);
60
+ inHunk = true;
61
+ continue;
62
+ }
63
+ if (!inHunk)
64
+ continue;
65
+ if (raw.startsWith("+++") || raw.startsWith("---"))
66
+ continue;
67
+ if (raw.startsWith("+")) {
68
+ added.push({ file, line, text: raw.slice(1) });
69
+ line += 1;
70
+ }
71
+ else if (raw.startsWith("-")) {
72
+ // a removed line: the new file's numbering does not advance
73
+ }
74
+ else if (raw.startsWith("\\")) {
75
+ // ""
76
+ }
77
+ else {
78
+ line += 1;
79
+ }
80
+ }
81
+ return { deleted, added };
82
+ };
83
+ const vitestLike = /\bTests\b[^\n]*?(\d+)\s+passed/u;
84
+ const jestLike = /\bTests:\s[^\n]*?(\d+)\s+passed/u;
85
+ const pytestLike = /(?:^|\n)[^\n]*?\b(\d+)\s+passed\b[^\n]*\bin\s+[\d.]+s/u;
86
+ const cargoLike = /test result:[^\n]*?(\d+)\s+passed/u;
87
+ const mochaLike = /(?:^|\n)\s*(\d+)\s+passing\b/u;
88
+ const junitLike = /Tests run:\s*(\d+),\s*Failures:\s*(\d+),\s*Errors:\s*(\d+)(?:,\s*Skipped:\s*(\d+))?/gu;
89
+ /**
90
+ * The passed-test count in a test runner's output, when a summary line the
91
+ * guard knows is present (Vitest, Jest, pytest, cargo test, mocha, JUnit
92
+ * via Maven/Gradle); `undefined` otherwise, which the guard reports as an
93
+ * Info rather than a verdict.
94
+ */
95
+ export const passedCountIn = (output) => {
96
+ for (const pattern of [vitestLike, jestLike, cargoLike, pytestLike, mochaLike]) {
97
+ const match = pattern.exec(output);
98
+ if (match?.[1] !== undefined) {
99
+ return Number.parseInt(match[1], 10);
100
+ }
101
+ }
102
+ // Maven prints a line per class and one grand total; the largest run is the total.
103
+ let largestRun = -1;
104
+ let passedOfLargest;
105
+ junitLike.lastIndex = 0;
106
+ for (let match = junitLike.exec(output); match !== null; match = junitLike.exec(output)) {
107
+ const run = Number.parseInt(match[1] ?? "0", 10);
108
+ const failures = Number.parseInt(match[2] ?? "0", 10);
109
+ const errors = Number.parseInt(match[3] ?? "0", 10);
110
+ const skipped = Number.parseInt(match[4] ?? "0", 10);
111
+ if (run >= largestRun) {
112
+ largestRun = run;
113
+ passedOfLargest = run - failures - errors - skipped;
114
+ }
115
+ }
116
+ return passedOfLargest;
117
+ };
118
+ export const oracleIssuePrefix = "oracle: ";
119
+ /**
120
+ * The guard's verdict on a change: one Critical per deleted test file, one
121
+ * per added marker (with `file:line`), one for a passed-count drop; empty
122
+ * when `declared` (the plan entry says tests may change). Counts are judged
123
+ * only when both are known; a caller reports the unknown case as an Info.
124
+ */
125
+ export const checkOracle = (diff, counts, rules, declared) => {
126
+ if (declared) {
127
+ return [];
128
+ }
129
+ const testFile = new RegExp(rules.testFiles, "u");
130
+ const issues = [];
131
+ for (const path of diff.deleted) {
132
+ if (testFile.test(path)) {
133
+ issues.push(ReviewIssue.make({
134
+ severity: "Critical",
135
+ title: `${oracleIssuePrefix}test file deleted: ${path}`,
136
+ description: "Restore it. A story may not delete a test unless its plan entry declares `testsChange: true`.",
137
+ file: path
138
+ }));
139
+ }
140
+ }
141
+ for (const line of diff.added) {
142
+ if (!testFile.test(line.file))
143
+ continue;
144
+ const marker = rules.markers.find((candidate) => line.text.includes(candidate));
145
+ if (marker === undefined)
146
+ continue;
147
+ issues.push(ReviewIssue.make({
148
+ severity: "Critical",
149
+ title: `${oracleIssuePrefix}skip or focus marker added: ${marker.trim()}`,
150
+ description: `${line.file}:${line.line}: ${line.text.trim()}\nRemove the marker and make the test pass, or report the test as wrong in your Findings.`,
151
+ file: line.file,
152
+ line: line.line
153
+ }));
154
+ }
155
+ if (counts?.base !== undefined && counts.current !== undefined && counts.current < counts.base) {
156
+ issues.push(ReviewIssue.make({
157
+ severity: "Critical",
158
+ title: `${oracleIssuePrefix}fewer tests pass than on the base (${counts.current} < ${counts.base})`,
159
+ description: "Tests were removed, skipped or no longer discovered. Restore them; declare `testsChange: true` on the story if the change is intended."
160
+ }));
161
+ }
162
+ return issues;
163
+ };
164
+ export const isOracleIssue = (issue) => issue.title.startsWith(oracleIssuePrefix);
165
+ //# sourceMappingURL=OracleGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OracleGuard.js","sourceRoot":"","sources":["../src/OracleGuard.ts"],"names":[],"mappings":"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"}
package/dist/Pack.d.ts CHANGED
@@ -3,6 +3,7 @@ import * as Schema from "effect/Schema";
3
3
  import { Dimension } from "@llm4ts/core/eval/Eval";
4
4
  import type { ConsolidateRules } from "./Domains.ts";
5
5
  import { PlanParseError } from "./FlowError.ts";
6
+ import { type OracleRules } from "./OracleGuard.ts";
6
7
  import { type Reviewer } from "./Reviewer.ts";
7
8
  import { CoverageRule } from "./SpecChecks.ts";
8
9
  import type { WorkspaceError, WorkspaceShape } from "./Workspace.ts";
@@ -54,6 +55,12 @@ export interface Pack {
54
55
  * fragment as context (`context:`). Absent: every program is its own feature.
55
56
  */
56
57
  readonly consolidate: ConsolidateRules | undefined;
58
+ /**
59
+ * The `## Oracle` section (ADR 0027): `- tests: <regex>` for what a test
60
+ * file is and `- markers: a, b` for extra skip or focus markers, merged
61
+ * over the defaults. Absent: the defaults.
62
+ */
63
+ readonly oracle: OracleRules | undefined;
57
64
  readonly dir: string;
58
65
  readonly gate: (name: string) => ReadonlyArray<string> | undefined;
59
66
  readonly prompt: (name: string) => string | undefined;