@webappwiz/cli 0.0.7 → 0.0.9
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 +19 -39
- package/{index-6km6e845.js → index-g81gg9gz.js} +123 -32
- package/{index-3p0t2exn.js → index-htwb54c6.js} +5 -7
- package/index-pyjg1rtk.js +373 -0
- package/index.js +10 -43
- package/judge.d.ts +12 -48
- package/judge.js +2 -4
- package/mode.d.ts +4 -6
- package/package.json +4 -8
- package/progress.d.ts +64 -0
- package/report.d.ts +14 -30
- package/rules.d.ts +0 -10
- package/rules.js +2 -4
- package/webappwiz.js +10 -43
- package/cost.d.ts +0 -45
- package/index-3k3rtw49.js +0 -128
- package/index-jbrs6gqt.js +0 -418
- package/signoff.d.ts +0 -63
- package/signoff.js +0 -7
package/progress.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type Timer } from "webappwiz/time";
|
|
2
|
+
/**
|
|
3
|
+
* Where live progress draws. `tty` is whether a line can be redrawn in
|
|
4
|
+
* place: without one, judge stays line-by-line and never writes here.
|
|
5
|
+
*/
|
|
6
|
+
export interface Screen {
|
|
7
|
+
tty: boolean;
|
|
8
|
+
write(text: string): void;
|
|
9
|
+
}
|
|
10
|
+
/** The terminal this process writes to. */
|
|
11
|
+
export declare const terminal: () => Screen;
|
|
12
|
+
/** A run as the status line shows it: how far along, what it is on, what it
|
|
13
|
+
* has spent, and what it has found. */
|
|
14
|
+
export interface RunView {
|
|
15
|
+
/** Calls finished. */
|
|
16
|
+
done: number;
|
|
17
|
+
/** Calls the run will make in all. */
|
|
18
|
+
total: number;
|
|
19
|
+
/** Files the calls out right now are reading. Every review names at least
|
|
20
|
+
* one, so zero here is the same as nothing running. */
|
|
21
|
+
files: number;
|
|
22
|
+
/** Tokens spent so far, when any agent has reported usage. */
|
|
23
|
+
tokens?: number;
|
|
24
|
+
/** Violations found so far; said aloud once the first call is home. */
|
|
25
|
+
problems: number;
|
|
26
|
+
}
|
|
27
|
+
/** The spinner's walk, one step per tick while any call is out. */
|
|
28
|
+
export declare const FRAMES: string[];
|
|
29
|
+
/**
|
|
30
|
+
* The status line. Pure, so what it says is testable without a terminal:
|
|
31
|
+
* the `Progress` around it only draws and redraws it. `frame` indexes the
|
|
32
|
+
* spinner's walk; with nothing running there is nothing to spin.
|
|
33
|
+
*/
|
|
34
|
+
export declare function render(view: RunView, frame?: number): string;
|
|
35
|
+
/** What a `Progress` paces its spinner with; the real one by default. */
|
|
36
|
+
export interface ProgressOptions {
|
|
37
|
+
timer?: Timer;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The live line a run draws while agents are out: progress over the calls
|
|
41
|
+
* and the tokens they have spent, redrawn on every event and spun on a
|
|
42
|
+
* tick between them. `stop` takes the line down, and whatever prints next
|
|
43
|
+
* lands where it was.
|
|
44
|
+
*/
|
|
45
|
+
export declare class Progress {
|
|
46
|
+
private screen;
|
|
47
|
+
private total;
|
|
48
|
+
private done;
|
|
49
|
+
private files;
|
|
50
|
+
private problems;
|
|
51
|
+
private tokens;
|
|
52
|
+
private drawn;
|
|
53
|
+
private frame;
|
|
54
|
+
private ticking;
|
|
55
|
+
constructor(screen: Screen, total: number, opts?: ProgressOptions);
|
|
56
|
+
/** A call went out over this many files. */
|
|
57
|
+
started(files: number): void;
|
|
58
|
+
/** A call came home: the files it read, what it spent, what it found. */
|
|
59
|
+
finished(files: number, spent?: number, problems?: number): void;
|
|
60
|
+
/** Takes the line down for good; call it before printing the report. */
|
|
61
|
+
stop(): void;
|
|
62
|
+
private erase;
|
|
63
|
+
private draw;
|
|
64
|
+
}
|
package/report.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Violation } from "@webappwiz/rules";
|
|
2
2
|
import type { Duration } from "webappwiz/time";
|
|
3
|
-
import { type Overheads } from "./cost.js";
|
|
4
3
|
export declare const count: (total: number, word: string) => string;
|
|
5
4
|
/**
|
|
6
5
|
* Where one printed document stops and the next starts, named so a reader
|
|
@@ -11,7 +10,8 @@ export declare const count: (total: number, word: string) => string;
|
|
|
11
10
|
* the last document wants as much as the others want an opening one.
|
|
12
11
|
*/
|
|
13
12
|
export declare const divider: (name?: string) => string;
|
|
14
|
-
|
|
13
|
+
/** How every token figure prints: "14K", not "14,000". */
|
|
14
|
+
export declare const compact: Intl.NumberFormat;
|
|
15
15
|
/**
|
|
16
16
|
* What a plan costs to read, at the four-bytes-a-token rule of thumb. Rough on
|
|
17
17
|
* purpose: an estimate that needed a tokenizer, or an API call to count, would
|
|
@@ -19,28 +19,10 @@ export declare const usd: (amount: number) => string;
|
|
|
19
19
|
* decision it informs is only ever "is this the order of magnitude I meant".
|
|
20
20
|
*/
|
|
21
21
|
export declare const tokens: (bytes: number) => number;
|
|
22
|
-
/**
|
|
23
|
-
* Why the estimate is a floor: each call pays for the agent's own system
|
|
24
|
-
* prompt and for whatever it re-reads as it works, none of which is knowable
|
|
25
|
-
* from here.
|
|
26
|
-
*/
|
|
27
|
-
export declare function overBudget(estimate: number, budget: number, cost?: number): string;
|
|
28
|
-
/**
|
|
29
|
-
* The whole of what `--estimate` prints: the plan, then what it costs on each
|
|
30
|
-
* agent that has a price.
|
|
31
|
-
*
|
|
32
|
-
* Two columns, because the floor alone is misleading. It prices the files a
|
|
33
|
-
* plan can see, and a call also pays for the agent's own system prompt every
|
|
34
|
-
* time, which on a small repo is most of the bill. `overheads` carries what
|
|
35
|
-
* past runs measured that per-call charge to be, so an agent that has been run
|
|
36
|
-
* here gets a second figure worth trusting.
|
|
37
|
-
*/
|
|
38
|
-
export declare function estimate(files: number, rules: number, calls: number, tokens: number, overheads: Overheads): string[];
|
|
39
22
|
/**
|
|
40
23
|
* The plan, before the first agent starts. Counts calls rather than reviews
|
|
41
|
-
* because a call is what a run
|
|
42
|
-
* `[n/total]` headings below.
|
|
43
|
-
* `--estimate` prints, so it names no command it is not going to run.
|
|
24
|
+
* because a call is what a run spawns, and it is the denominator of the
|
|
25
|
+
* `[n/total]` headings below.
|
|
44
26
|
*/
|
|
45
27
|
export interface Planned {
|
|
46
28
|
files: number;
|
|
@@ -50,14 +32,12 @@ export interface Planned {
|
|
|
50
32
|
estimate: number;
|
|
51
33
|
/** Agent calls in flight at once, which is what the wall clock turns on. */
|
|
52
34
|
concurrency?: number;
|
|
53
|
-
/** What those calls are predicted to cost, when the agent has a price. */
|
|
54
|
-
cost?: number;
|
|
55
35
|
/** The command the run will spawn. */
|
|
56
36
|
agent?: string;
|
|
57
37
|
}
|
|
58
|
-
export declare function planned({ files, rules, calls, estimate, concurrency,
|
|
38
|
+
export declare function planned({ files, rules, calls, estimate, concurrency, agent, }: Planned): string[];
|
|
59
39
|
/** A finished review as the report prints it: what the call covered, what it
|
|
60
|
-
* found, and what it
|
|
40
|
+
* found, and what it read. */
|
|
61
41
|
export interface Finished {
|
|
62
42
|
/** The ids of the rules the review checked. */
|
|
63
43
|
rules: string[];
|
|
@@ -66,8 +46,12 @@ export interface Finished {
|
|
|
66
46
|
violations: Violation[];
|
|
67
47
|
/** How long this review's agent took. */
|
|
68
48
|
took: Duration;
|
|
69
|
-
/**
|
|
70
|
-
|
|
49
|
+
/** Tokens this review's call touched, when the agent reported usage. */
|
|
50
|
+
tokens?: number;
|
|
51
|
+
/** Which worker ran the call, 0-based. */
|
|
52
|
+
worker: number;
|
|
53
|
+
/** Tokens that worker has touched so far, this review included. */
|
|
54
|
+
workerTokens?: number;
|
|
71
55
|
done: number;
|
|
72
56
|
total: number;
|
|
73
57
|
}
|
|
@@ -75,11 +59,11 @@ export interface Finished {
|
|
|
75
59
|
* A finished review, as it should print the moment its agent returns: a status
|
|
76
60
|
* line sizing the call, then one finding per violation.
|
|
77
61
|
*/
|
|
78
|
-
export declare function finished({ rules, files, violations, took,
|
|
62
|
+
export declare function finished({ rules, files, violations, took, tokens, worker, workerTokens, done, total, }: Finished): string[];
|
|
79
63
|
/**
|
|
80
64
|
* One violation: a location a reader can click, what the code does that the
|
|
81
65
|
* rule forbids, and the line it happens on. The heading above names only the
|
|
82
66
|
* glob, so the finding says which of its rules this one breaks.
|
|
83
67
|
*/
|
|
84
68
|
export declare function finding(violation: Violation): string[];
|
|
85
|
-
export declare function summary(violations: Violation[], took: Duration,
|
|
69
|
+
export declare function summary(violations: Violation[], took: Duration, tokens?: number): string;
|
package/rules.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type Rule } from "@webappwiz/rules";
|
|
2
1
|
/**
|
|
3
2
|
* Every rule webappwiz judges itself by, named one by one. There is no preset
|
|
4
3
|
* to spread and nothing runs implicitly: a rule is here or it does not run.
|
|
@@ -9,12 +8,3 @@ import { type Rule } from "@webappwiz/rules";
|
|
|
9
8
|
* module for one of these to import.
|
|
10
9
|
*/
|
|
11
10
|
export declare const JUDGE_RULES: import("@webappwiz/rules").RuleSet;
|
|
12
|
-
/**
|
|
13
|
-
* What an agent weighs before merging a change, rather than what it checks a
|
|
14
|
-
* file against: whether the change needs a person to look at it.
|
|
15
|
-
*
|
|
16
|
-
* No command runs these. They are documents an agent reads and applies itself,
|
|
17
|
-
* which is why they carry no glob and no check, and `wiz rules show` prints
|
|
18
|
-
* them the same as any other.
|
|
19
|
-
*/
|
|
20
|
-
export declare const SIGNOFF_RULES: Rule[];
|
package/rules.js
CHANGED
package/webappwiz.js
CHANGED
|
@@ -4,17 +4,13 @@ import {
|
|
|
4
4
|
update,
|
|
5
5
|
update1 as update2,
|
|
6
6
|
version
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-g81gg9gz.js";
|
|
8
8
|
import {
|
|
9
|
-
JUDGE_RULES
|
|
10
|
-
|
|
11
|
-
} from "./index-3p0t2exn.js";
|
|
12
|
-
import {
|
|
13
|
-
Signoff
|
|
14
|
-
} from "./index-3k3rtw49.js";
|
|
9
|
+
JUDGE_RULES
|
|
10
|
+
} from "./index-htwb54c6.js";
|
|
15
11
|
import {
|
|
16
12
|
JudgeCommands
|
|
17
|
-
} from "./index-
|
|
13
|
+
} from "./index-pyjg1rtk.js";
|
|
18
14
|
|
|
19
15
|
// webappwiz.ts
|
|
20
16
|
import { AGENTS } from "@webappwiz/rules";
|
|
@@ -28,14 +24,7 @@ webappwiz.command("update").description("pin every webappwiz dependency in a tre
|
|
|
28
24
|
default: version,
|
|
29
25
|
description: "version to pin to"
|
|
30
26
|
}).action((opts, { log, fs }) => update2({ ...opts, log, fs }));
|
|
31
|
-
var judge = ({ log, fs, ps, clock, glob }) => new JudgeCommands(JUDGE_RULES, {
|
|
32
|
-
signoffRules: SIGNOFF_RULES,
|
|
33
|
-
log,
|
|
34
|
-
fs,
|
|
35
|
-
ps,
|
|
36
|
-
clock,
|
|
37
|
-
glob
|
|
38
|
-
});
|
|
27
|
+
var judge = ({ log, fs, ps, clock, glob }) => new JudgeCommands(JUDGE_RULES, { log, fs, ps, clock, glob });
|
|
39
28
|
webappwiz.command("judge").description("check a directory against the config, one agent per glob").arg("dir", t.string(), {
|
|
40
29
|
default: ".",
|
|
41
30
|
description: "directory to judge (default: .)"
|
|
@@ -46,39 +35,17 @@ webappwiz.command("judge").description("check a directory against the config, on
|
|
|
46
35
|
}).option("print", t.boolean(), {
|
|
47
36
|
default: false,
|
|
48
37
|
description: "print the prompts and run no agent at all"
|
|
49
|
-
}).option("estimate", t.boolean(), {
|
|
50
|
-
default: false,
|
|
51
|
-
description: "print what a run would read, and run nothing"
|
|
52
38
|
}).option("chunk", t.number(), {
|
|
53
39
|
default: 25,
|
|
54
40
|
description: "files per review"
|
|
55
41
|
}).option("since", t.optional(t.string()), {
|
|
56
42
|
description: "only check files added or changed since this git ref"
|
|
57
|
-
}).option("
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}).action((opts, deps) => judge(deps).judge(opts));
|
|
61
|
-
webappwiz.command("signoff").description("weigh a change against the rules that ask for a person").arg("dir", t.string(), {
|
|
62
|
-
default: ".",
|
|
63
|
-
description: "directory whose change is weighed (default: .)"
|
|
64
|
-
}).option("agent", t.optional(t.enum(Object.keys(AGENTS))), {
|
|
65
|
-
description: "model to weigh it with (default: the config's agent)"
|
|
66
|
-
}).option("exec", t.optional(t.string()), {
|
|
67
|
-
description: "command the prompt is passed to, instead of --agent"
|
|
68
|
-
}).option("print", t.boolean(), {
|
|
43
|
+
}).option("concurrency-override", t.optional(t.number()), {
|
|
44
|
+
description: "agent calls in flight at once, over the config's concurrency"
|
|
45
|
+
}).option("ci", t.boolean(), {
|
|
69
46
|
default: false,
|
|
70
|
-
description: "
|
|
71
|
-
}).
|
|
72
|
-
default: "main",
|
|
73
|
-
description: "the ref the change is measured against"
|
|
74
|
-
}).option("budget", t.number(), {
|
|
75
|
-
default: 200000,
|
|
76
|
-
description: "confirm before reading more than this many tokens"
|
|
77
|
-
}).action((opts, { log, ps, clock }) => new Signoff(SIGNOFF_RULES, JUDGE_RULES.agent, {
|
|
78
|
-
log,
|
|
79
|
-
ps,
|
|
80
|
-
clock
|
|
81
|
-
}).run(opts));
|
|
47
|
+
description: "line-by-line output with no live progress block"
|
|
48
|
+
}).action((opts, deps) => judge(deps).judge(opts));
|
|
82
49
|
var rules = webappwiz.group("rules").description("list and print the rules, to run or to read yourself");
|
|
83
50
|
rules.command("ls").description("list the rules").action((_opts, deps) => judge(deps).ls());
|
|
84
51
|
rules.command("show").description("print one rule in full, by the id `rules ls` gives it").arg("id", t.string(), { description: "rule id" }).action((opts, deps) => judge(deps).show(opts));
|
package/cost.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { type Fs } from "webappwiz/system";
|
|
2
|
-
/** The agents an estimate can price, which is every one `--agent` accepts. */
|
|
3
|
-
export declare const priced: () => string[];
|
|
4
|
-
/**
|
|
5
|
-
* What those tokens cost to read on that agent, or undefined for an agent with
|
|
6
|
-
* no published price, which is any `--exec` command.
|
|
7
|
-
*
|
|
8
|
-
* A floor twice over: it counts input only, and only the input a plan can see.
|
|
9
|
-
*/
|
|
10
|
-
export declare function floor(agent: string, tokens: number): number | undefined;
|
|
11
|
-
/**
|
|
12
|
-
* Dollars a single call costs beyond the files it was given, per agent.
|
|
13
|
-
*
|
|
14
|
-
* Everything the floor cannot see is charged per call, not per byte: the agent
|
|
15
|
-
* pays for its own system prompt every time it is spawned, and on this project
|
|
16
|
-
* that is most of a small call's bill. Measuring it per call is what lets a
|
|
17
|
-
* figure taken from a two-call run stand up to a fifteen-call one.
|
|
18
|
-
*/
|
|
19
|
-
export type Overheads = Record<string, number>;
|
|
20
|
-
/**
|
|
21
|
-
* What past runs in `root` measured, empty until one has finished there. A
|
|
22
|
-
* missing or unreadable file is empty rather than an error: a calibration is a
|
|
23
|
-
* convenience, and losing it costs the caller a worse estimate, not a run.
|
|
24
|
-
*/
|
|
25
|
-
export interface OverheadsOptions {
|
|
26
|
-
/** What the record is read through; the real filesystem by default. */
|
|
27
|
-
fs?: Fs;
|
|
28
|
-
}
|
|
29
|
-
export declare function overheads(dir: string, opts?: OverheadsOptions): Promise<Overheads>;
|
|
30
|
-
/**
|
|
31
|
-
* Records what a call on this agent costs over its floor, so the next
|
|
32
|
-
* `--estimate` has something better than one. Other agents are left alone,
|
|
33
|
-
* since each is a separate measurement.
|
|
34
|
-
*/
|
|
35
|
-
export interface CalibrateOptions {
|
|
36
|
-
/** What the record is written through; the real filesystem by default. */
|
|
37
|
-
fs?: Fs;
|
|
38
|
-
}
|
|
39
|
-
export declare function calibrate(dir: string, agent: string, call: number, opts?: CalibrateOptions): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* What a plan costs on one agent: the price of the files it names, plus what
|
|
42
|
-
* every call charges on top. Undefined for an agent with no listed price, and
|
|
43
|
-
* the floor alone until a run has measured one.
|
|
44
|
-
*/
|
|
45
|
-
export declare function predict(agent: string, tokens: number, calls: number, measured: Overheads): number | undefined;
|
package/index-3k3rtw49.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ask,
|
|
3
|
-
count,
|
|
4
|
-
diff,
|
|
5
|
-
divider,
|
|
6
|
-
mode,
|
|
7
|
-
overBudget,
|
|
8
|
-
tokens,
|
|
9
|
-
usd
|
|
10
|
-
} from "./index-jbrs6gqt.js";
|
|
11
|
-
|
|
12
|
-
// signoff.ts
|
|
13
|
-
import {
|
|
14
|
-
agentCommand,
|
|
15
|
-
Harness,
|
|
16
|
-
prompt as reviewPrompt
|
|
17
|
-
} from "@webappwiz/rules";
|
|
18
|
-
import { ConsoleLogger, color } from "webappwiz/log";
|
|
19
|
-
import { NodePs } from "webappwiz/system";
|
|
20
|
-
import { SystemClock } from "webappwiz/time";
|
|
21
|
-
class Signoff {
|
|
22
|
-
rules;
|
|
23
|
-
defaultAgent;
|
|
24
|
-
confirmer;
|
|
25
|
-
log;
|
|
26
|
-
ps;
|
|
27
|
-
clock;
|
|
28
|
-
constructor(rules, defaultAgent, opts = {}) {
|
|
29
|
-
this.rules = rules;
|
|
30
|
-
this.defaultAgent = defaultAgent;
|
|
31
|
-
this.confirmer = opts.confirmer ?? ask;
|
|
32
|
-
this.log = opts.log ?? new ConsoleLogger;
|
|
33
|
-
this.ps = opts.ps ?? new NodePs;
|
|
34
|
-
this.clock = opts.clock ?? new SystemClock;
|
|
35
|
-
}
|
|
36
|
-
async run(opts) {
|
|
37
|
-
if (mode(opts) === "print") {
|
|
38
|
-
this.print();
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const dir = opts.dir.replace(/\/+$/, "") || "/";
|
|
42
|
-
const { patch, added } = await diff(dir, opts.since, { ps: this.ps });
|
|
43
|
-
if (patch === "" && added.length === 0) {
|
|
44
|
-
this.log.info(`nothing has changed since ${opts.since}`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
const agent = agentCommand(opts.exec === undefined ? { agent: opts.agent ?? this.defaultAgent } : opts);
|
|
48
|
-
const review = this.review(patch, added, opts.since);
|
|
49
|
-
const predicted = tokens(review.bytes ?? 0);
|
|
50
|
-
this.log.info(`weighing ${opts.since}..working tree against ` + `${count(this.rules.length, "rule")}, reading ` + `${predicted}+ tokens with ${agent.label}`);
|
|
51
|
-
if (predicted > opts.budget) {
|
|
52
|
-
this.log.info(overBudget(predicted, opts.budget));
|
|
53
|
-
if (!await this.confirmer.confirm("Run anyway?")) {
|
|
54
|
-
throw new Error("over budget");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
this.say(await this.judge(review, agent, dir));
|
|
58
|
-
}
|
|
59
|
-
async judge(review, agent, dir) {
|
|
60
|
-
const harness = new Harness({
|
|
61
|
-
log: this.log,
|
|
62
|
-
ps: this.ps,
|
|
63
|
-
clock: this.clock
|
|
64
|
-
});
|
|
65
|
-
harness.events.on("finished", ({ took, cost }) => {
|
|
66
|
-
const spent = cost === undefined ? "" : ` ${usd(cost)}`;
|
|
67
|
-
this.log.info(color.gray(`read in ${took.human()}${spent}`));
|
|
68
|
-
});
|
|
69
|
-
return await harness.run([review], agent, { cwd: dir });
|
|
70
|
-
}
|
|
71
|
-
say(findings) {
|
|
72
|
-
if (findings.length === 0) {
|
|
73
|
-
this.log.info(color.green("✓ nothing in this change needs a person"));
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
for (const finding of findings) {
|
|
77
|
-
const where = finding.file === undefined ? "" : `${color.bold(finding.file + (finding.line === undefined ? "" : `:${finding.line}`))} `;
|
|
78
|
-
this.log.info(` ${where}${finding.message} ${color.gray(`(${finding.rule})`)}`);
|
|
79
|
-
}
|
|
80
|
-
throw new Error(`${count(findings.length, "reason")} to escalate rather than merge`);
|
|
81
|
-
}
|
|
82
|
-
review(patch, added, ref) {
|
|
83
|
-
const draft = {
|
|
84
|
-
rules: this.rules,
|
|
85
|
-
label: "signoff",
|
|
86
|
-
context: [
|
|
87
|
-
`The change, as \`git diff ${ref}\` prints it:`,
|
|
88
|
-
`\`\`\`diff
|
|
89
|
-
${patch}
|
|
90
|
-
\`\`\``,
|
|
91
|
-
...added.length === 0 ? [] : [
|
|
92
|
-
"These files are new and are in no diff yet. Read each one from " + "your working directory:",
|
|
93
|
-
added.map((file) => `- ${file}`).join(`
|
|
94
|
-
`)
|
|
95
|
-
]
|
|
96
|
-
].join(`
|
|
97
|
-
|
|
98
|
-
`),
|
|
99
|
-
instructions: WEIGHING
|
|
100
|
-
};
|
|
101
|
-
return { ...draft, bytes: Buffer.byteLength(reviewPrompt(draft)) };
|
|
102
|
-
}
|
|
103
|
-
print() {
|
|
104
|
-
if (this.rules.length === 0) {
|
|
105
|
-
this.log.info("no signoff rules");
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
this.log.info("Weigh your change against each rule below. Anything that needs " + "review goes to a person instead of trunk.");
|
|
109
|
-
for (const rule of this.rules) {
|
|
110
|
-
this.log.info(`
|
|
111
|
-
${divider(rule.id)}
|
|
112
|
-
`);
|
|
113
|
-
this.log.info(rule.document.trim());
|
|
114
|
-
}
|
|
115
|
-
this.log.info(`
|
|
116
|
-
${divider()}`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
var WEIGHING = [
|
|
120
|
-
"These rules decide one thing: whether this change can merge on its own, " + "or needs a person to look at it first.",
|
|
121
|
-
"",
|
|
122
|
-
"Each rule's `Ships` section is what merges with nobody looking, and its " + "`Needs review` section is what does not. Report a violation only for " + "what the `Needs review` side covers, and only where the change " + "actually does it.",
|
|
123
|
-
"",
|
|
124
|
-
"These rules are about the change as a whole, so leave `file` and `line` " + "out unless one place in the change is the whole of the answer."
|
|
125
|
-
].join(`
|
|
126
|
-
`);
|
|
127
|
-
|
|
128
|
-
export { Signoff };
|