@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.
@@ -0,0 +1,373 @@
1
+ // judge.ts
2
+ import {
3
+ agentCommand,
4
+ Files,
5
+ Harness,
6
+ prompt as reviewPrompt
7
+ } from "@webappwiz/rules";
8
+ import { ConsoleLogger, color as color4 } from "webappwiz/log";
9
+ import {
10
+ NodeFs,
11
+ NodeGlob,
12
+ NodePs as NodePs2
13
+ } from "webappwiz/system";
14
+ import { SystemClock } from "webappwiz/time";
15
+
16
+ // changed.ts
17
+ import { NodePs } from "webappwiz/system";
18
+ async function changed(dir, ref, opts = {}) {
19
+ const ps = opts.ps ?? new NodePs;
20
+ const files = new Set;
21
+ for (const argv of [
22
+ ["diff", "--name-only", "--diff-filter=d", "--relative", ref],
23
+ ["ls-files", "--others", "--exclude-standard"]
24
+ ]) {
25
+ for (const line of (await git(ps, dir, argv)).split(`
26
+ `)) {
27
+ if (line !== "") {
28
+ files.add(line);
29
+ }
30
+ }
31
+ }
32
+ return files;
33
+ }
34
+ async function git(ps, dir, argv) {
35
+ const { exitCode, stdout, stderr } = await ps.spawnCapture([
36
+ "git",
37
+ "-C",
38
+ dir,
39
+ ...argv
40
+ ]);
41
+ if (exitCode !== 0) {
42
+ throw new Error(`git ${argv[0]} failed in ${dir}: ${stderr.trim() || `exit ${exitCode}`}`);
43
+ }
44
+ return stdout;
45
+ }
46
+
47
+ // mode.ts
48
+ function mode({ print, agent, exec }) {
49
+ const named = [
50
+ print === true ? "--print" : undefined,
51
+ agent === undefined ? undefined : "--agent",
52
+ exec === undefined ? undefined : "--exec"
53
+ ].filter((flag) => flag !== undefined);
54
+ if (named.length > 1) {
55
+ throw new Error(`${named.join(" and ")} are different things to do with one run, so pass one`);
56
+ }
57
+ return print === true ? "print" : "run";
58
+ }
59
+
60
+ // progress.ts
61
+ import { color as color3 } from "webappwiz/log";
62
+ import { Duration, SystemTimer } from "webappwiz/time";
63
+
64
+ // report.ts
65
+ import { color as color2 } from "webappwiz/log";
66
+
67
+ // table.ts
68
+ import { color } from "webappwiz/log";
69
+ var table = (rows) => {
70
+ const width = (cell) => color.strip(cell).length;
71
+ const widths = rows[0]?.map((_, i) => Math.max(...rows.map((row) => width(row[i] ?? ""))));
72
+ return rows.map((row) => row.map((cell, i) => cell.padEnd((widths?.[i] ?? 0) + cell.length - width(cell))).join(" ").trimEnd());
73
+ };
74
+
75
+ // report.ts
76
+ var count = (total, word) => `${total} ${word}${total === 1 ? "" : "s"}`;
77
+ var divider = (name) => {
78
+ if (name === undefined) {
79
+ return color2.dim("-".repeat(72));
80
+ }
81
+ const opening = `--- ${name} `;
82
+ return color2.dim(opening.padEnd(Math.max(72, opening.length + 3), "-"));
83
+ };
84
+ var compact = new Intl.NumberFormat("en", { notation: "compact" });
85
+ var tokens = (bytes) => Math.ceil(bytes / 4);
86
+ function planned({
87
+ files,
88
+ rules,
89
+ calls,
90
+ estimate,
91
+ concurrency,
92
+ agent
93
+ }) {
94
+ const rows = [
95
+ [color2.dim("files"), String(files)],
96
+ [color2.dim("rules"), String(rules)],
97
+ [color2.dim("calls"), String(calls)],
98
+ ...concurrency === undefined ? [] : [[color2.dim("workers"), String(concurrency)]],
99
+ [color2.dim("reading"), `${compact.format(estimate)}+ tokens`]
100
+ ];
101
+ if (agent !== undefined) {
102
+ rows.push([color2.dim("agent"), agent]);
103
+ }
104
+ return ["", ...table(rows).map((line) => ` ${line}`), ""];
105
+ }
106
+ function finished({
107
+ rules,
108
+ files,
109
+ violations,
110
+ took,
111
+ tokens: tokens2,
112
+ worker,
113
+ workerTokens,
114
+ done,
115
+ total
116
+ }) {
117
+ const heading = `${color2.gray(`[${done}/${total}]`)} ` + color2.gray(`(${count(rules.length, "rule")}, ${count(files, "file")})`);
118
+ const spent = tokens2 === undefined ? "" : ` ${compact.format(tokens2)} tokens` + (workerTokens === undefined ? "" : ` (w${worker + 1}: ${compact.format(workerTokens)})`);
119
+ const tail = `${color2.gray(`in ${took.human()}${spent}`)}`;
120
+ if (violations.length === 0) {
121
+ return [`${color2.green("✓")} ${heading}: clean ${tail}`];
122
+ }
123
+ return [
124
+ `${color2.red("✗")} ${heading}: ${count(violations.length, "problem")} ${tail}`,
125
+ ...violations.flatMap(finding)
126
+ ];
127
+ }
128
+ function finding(violation) {
129
+ const level = violation.level === "error" ? color2.red("error") : color2.yellow(violation.level);
130
+ const lines = [
131
+ ` ${color2.bold(`${violation.file}:${violation.line}`)} ${level} ${violation.message} ${color2.gray(`(${violation.id})`)}`
132
+ ];
133
+ if (violation.code !== "") {
134
+ lines.push(color2.gray(` │ ${violation.code}`));
135
+ }
136
+ return lines;
137
+ }
138
+ function summary(violations, took, tokens2) {
139
+ const spent = tokens2 === undefined ? "" : ` ${compact.format(tokens2)} tokens total`;
140
+ const elapsed = color2.gray(`in ${took.human()}${spent}`);
141
+ if (violations.length === 0) {
142
+ return `${color2.green("✓ no violations")} ${elapsed}`;
143
+ }
144
+ const errors = violations.filter((violation) => violation.level === "error").length;
145
+ const line = `✖ ${count(violations.length, "problem")} (${count(errors, "error")}, ${count(violations.length - errors, "warning")})`;
146
+ return `${errors > 0 ? color2.red(line) : color2.yellow(line)} ${elapsed}`;
147
+ }
148
+
149
+ // progress.ts
150
+ var terminal = () => ({
151
+ tty: process.stdout.isTTY === true,
152
+ write: (text) => process.stdout.write(text)
153
+ });
154
+ var BAR = 20;
155
+ var FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
156
+ function render(view, frame = 0) {
157
+ const spin = view.files === 0 ? " " : FRAMES[frame % FRAMES.length] ?? " ";
158
+ const filled = Math.round(BAR * view.done / Math.max(1, view.total));
159
+ const bar = color3.green("█".repeat(filled)) + color3.dim("░".repeat(BAR - filled));
160
+ const judging = view.files === 0 ? "" : ` · judging ${count(view.files, "file")}`;
161
+ const spent = view.tokens === undefined ? "" : ` · ${compact.format(view.tokens)} tokens`;
162
+ const found = view.done === 0 ? "" : ` · ${view.problems === 0 ? "clean so far" : count(view.problems, "problem")}`;
163
+ return `${color3.green(spin)} ${bar} ${color3.gray(`${view.done}/${view.total} calls${judging}${spent}${found}`)}`;
164
+ }
165
+
166
+ class Progress {
167
+ screen;
168
+ total;
169
+ done = 0;
170
+ files = 0;
171
+ problems = 0;
172
+ tokens;
173
+ drawn = false;
174
+ frame = 0;
175
+ ticking;
176
+ constructor(screen, total, opts = {}) {
177
+ this.screen = screen;
178
+ this.total = total;
179
+ const timer = opts.timer ?? new SystemTimer;
180
+ this.ticking = timer.setInterval(() => {
181
+ this.frame += 1;
182
+ this.draw();
183
+ }, Duration.ms(100));
184
+ }
185
+ started(files) {
186
+ this.files += files;
187
+ this.draw();
188
+ }
189
+ finished(files, spent, problems = 0) {
190
+ this.files -= files;
191
+ this.done += 1;
192
+ this.problems += problems;
193
+ if (spent !== undefined) {
194
+ this.tokens = (this.tokens ?? 0) + spent;
195
+ }
196
+ this.draw();
197
+ }
198
+ stop() {
199
+ this.ticking.dispose();
200
+ this.erase();
201
+ }
202
+ erase() {
203
+ if (this.drawn) {
204
+ this.screen.write("\x1B[1A\r\x1B[0J");
205
+ this.drawn = false;
206
+ }
207
+ }
208
+ draw() {
209
+ const line = render({
210
+ done: this.done,
211
+ total: this.total,
212
+ files: this.files,
213
+ tokens: this.tokens,
214
+ problems: this.problems
215
+ }, this.frame);
216
+ this.erase();
217
+ this.screen.write(`${line}
218
+ `);
219
+ this.drawn = true;
220
+ }
221
+ }
222
+
223
+ // judge.ts
224
+ var estimated = (reviews) => tokens(reviews.reduce((bytes, review) => bytes + review.bytes, 0));
225
+ var title = (rule) => /^#\s+(.+)$/m.exec(rule.document)?.[1]?.trim() ?? rule.id;
226
+
227
+ class JudgeCommands {
228
+ rules;
229
+ screen;
230
+ log;
231
+ fs;
232
+ ps;
233
+ clock;
234
+ glob;
235
+ constructor(rules, opts = {}) {
236
+ this.rules = rules;
237
+ this.screen = opts.screen ?? terminal();
238
+ this.log = opts.log ?? new ConsoleLogger;
239
+ this.fs = opts.fs ?? new NodeFs;
240
+ this.ps = opts.ps ?? new NodePs2;
241
+ this.clock = opts.clock ?? new SystemClock;
242
+ this.glob = opts.glob ?? new NodeGlob;
243
+ }
244
+ ls() {
245
+ const rows = [["id", "rule", "level", "files"].map(color4.dim)];
246
+ for (const rule of this.rules.rules) {
247
+ rows.push([rule.id, title(rule), rule.level, rule.files]);
248
+ }
249
+ this.log.info(table(rows).join(`
250
+ `));
251
+ }
252
+ show(opts) {
253
+ const all = this.rules.rules;
254
+ const rule = all.find((candidate) => candidate.id === opts.id);
255
+ if (!rule) {
256
+ throw new Error(`no rule "${opts.id}". Known ids: ${all.map((candidate) => candidate.id).join(", ")}`);
257
+ }
258
+ const rows = [
259
+ [color4.dim("id"), rule.id],
260
+ [color4.dim("rule"), title(rule)],
261
+ [color4.dim("level"), rule.level],
262
+ [color4.dim("files"), rule.files]
263
+ ];
264
+ this.log.info(table(rows).join(`
265
+ `));
266
+ this.log.info("");
267
+ this.log.info(rule.document.trim());
268
+ }
269
+ async judge(opts) {
270
+ const how = mode(opts);
271
+ const config = this.rules;
272
+ const rules = config.rules;
273
+ const dir = opts.dir.replace(/\/+$/, "") || "/";
274
+ const only = opts.since === undefined ? undefined : await changed(dir, opts.since, { ps: this.ps });
275
+ if (only?.size === 0) {
276
+ this.log.info(`nothing has changed since ${opts.since}`);
277
+ return;
278
+ }
279
+ const files = new Files({ log: this.log, fs: this.fs, glob: this.glob });
280
+ const reviews = await files.plan(rules, dir, {
281
+ chunk: opts.chunk,
282
+ only
283
+ });
284
+ if (how === "print") {
285
+ for (const review of reviews) {
286
+ this.log.info(`
287
+ ${divider(`${review.label} (${count(review.files.length, "file")})`)}
288
+ `);
289
+ this.log.info(reviewPrompt(review));
290
+ }
291
+ this.log.info(`
292
+ ${divider()}`);
293
+ return;
294
+ }
295
+ const read = new Set(reviews.flatMap((review) => review.files)).size;
296
+ const agent = this.agent(config, opts);
297
+ const concurrency = opts["concurrency-override"] ?? config.concurrency;
298
+ const started = this.clock.now();
299
+ this.log.info(planned({
300
+ files: read,
301
+ rules: rules.length,
302
+ calls: reviews.length,
303
+ estimate: estimated(reviews),
304
+ concurrency,
305
+ agent: agent.label
306
+ }).join(`
307
+ `));
308
+ const found = [];
309
+ const byWorker = new Map;
310
+ let spent;
311
+ const progress = opts.ci !== true && this.screen.tty ? new Progress(this.screen, reviews.length) : undefined;
312
+ const deferred = [];
313
+ const harness = new Harness({
314
+ log: this.log,
315
+ ps: this.ps,
316
+ clock: this.clock
317
+ });
318
+ harness.events.on("started", ({ at }) => progress?.started(reviews[at]?.files.length ?? 0));
319
+ harness.events.on("finished", (review) => {
320
+ const at = reviews[review.at];
321
+ if (!at) {
322
+ return;
323
+ }
324
+ let workerTokens;
325
+ if (review.tokens !== undefined) {
326
+ workerTokens = (byWorker.get(review.worker) ?? 0) + review.tokens;
327
+ byWorker.set(review.worker, workerTokens);
328
+ spent = (spent ?? 0) + review.tokens;
329
+ }
330
+ const violations2 = files.violations(at, review.findings, dir);
331
+ found[review.at] = violations2;
332
+ progress?.finished(at.files.length, review.tokens, violations2.length);
333
+ const lines = finished({
334
+ rules: review.rules,
335
+ files: at.files.length,
336
+ violations: violations2,
337
+ took: review.took,
338
+ tokens: review.tokens,
339
+ worker: review.worker,
340
+ workerTokens,
341
+ done: review.done,
342
+ total: review.total
343
+ });
344
+ if (progress) {
345
+ deferred[review.done - 1] = lines;
346
+ } else {
347
+ for (const line of lines) {
348
+ this.log.info(line);
349
+ }
350
+ }
351
+ });
352
+ try {
353
+ await harness.run(reviews, agent, { cwd: dir, concurrency });
354
+ } finally {
355
+ progress?.stop();
356
+ }
357
+ for (const line of deferred.flat()) {
358
+ this.log.info(line);
359
+ }
360
+ const violations = found.flat();
361
+ this.log.info("");
362
+ this.log.info(summary(violations, this.clock.now().subtract(started), spent));
363
+ const errors = violations.filter((violation) => violation.level === "error").length;
364
+ if (errors > 0) {
365
+ throw new Error(count(errors, "error"));
366
+ }
367
+ }
368
+ agent(config, opts) {
369
+ return agentCommand(opts.exec === undefined ? { agent: opts.agent ?? config.agent } : opts);
370
+ }
371
+ }
372
+
373
+ export { table, JudgeCommands };
package/index.js CHANGED
@@ -6,17 +6,13 @@ import {
6
6
  update,
7
7
  update1 as update2,
8
8
  version
9
- } from "./index-6km6e845.js";
9
+ } from "./index-g81gg9gz.js";
10
10
  import {
11
- JUDGE_RULES,
12
- SIGNOFF_RULES
13
- } from "./index-3p0t2exn.js";
14
- import {
15
- Signoff
16
- } from "./index-3k3rtw49.js";
11
+ JUDGE_RULES
12
+ } from "./index-htwb54c6.js";
17
13
  import {
18
14
  JudgeCommands
19
- } from "./index-jbrs6gqt.js";
15
+ } from "./index-pyjg1rtk.js";
20
16
 
21
17
  // index.ts
22
18
  import { NodeFs, NodeGlob } from "webappwiz/system";
@@ -34,14 +30,7 @@ webappwiz.command("update").description("pin every webappwiz dependency in a tre
34
30
  default: version,
35
31
  description: "version to pin to"
36
32
  }).action((opts, { log, fs }) => update2({ ...opts, log, fs }));
37
- var judge = ({ log, fs, ps, clock, glob }) => new JudgeCommands(JUDGE_RULES, {
38
- signoffRules: SIGNOFF_RULES,
39
- log,
40
- fs,
41
- ps,
42
- clock,
43
- glob
44
- });
33
+ var judge = ({ log, fs, ps, clock, glob }) => new JudgeCommands(JUDGE_RULES, { log, fs, ps, clock, glob });
45
34
  webappwiz.command("judge").description("check a directory against the config, one agent per glob").arg("dir", t.string(), {
46
35
  default: ".",
47
36
  description: "directory to judge (default: .)"
@@ -52,39 +41,17 @@ webappwiz.command("judge").description("check a directory against the config, on
52
41
  }).option("print", t.boolean(), {
53
42
  default: false,
54
43
  description: "print the prompts and run no agent at all"
55
- }).option("estimate", t.boolean(), {
56
- default: false,
57
- description: "print what a run would read, and run nothing"
58
44
  }).option("chunk", t.number(), {
59
45
  default: 25,
60
46
  description: "files per review"
61
47
  }).option("since", t.optional(t.string()), {
62
48
  description: "only check files added or changed since this git ref"
63
- }).option("budget", t.number(), {
64
- default: 200000,
65
- description: "confirm before reading more than this many tokens"
66
- }).action((opts, deps) => judge(deps).judge(opts));
67
- webappwiz.command("signoff").description("weigh a change against the rules that ask for a person").arg("dir", t.string(), {
68
- default: ".",
69
- description: "directory whose change is weighed (default: .)"
70
- }).option("agent", t.optional(t.enum(Object.keys(AGENTS))), {
71
- description: "model to weigh it with (default: the config's agent)"
72
- }).option("exec", t.optional(t.string()), {
73
- description: "command the prompt is passed to, instead of --agent"
74
- }).option("print", t.boolean(), {
49
+ }).option("concurrency-override", t.optional(t.number()), {
50
+ description: "agent calls in flight at once, over the config's concurrency"
51
+ }).option("ci", t.boolean(), {
75
52
  default: false,
76
- description: "print the rules to apply yourself, and run no agent"
77
- }).option("since", t.string(), {
78
- default: "main",
79
- description: "the ref the change is measured against"
80
- }).option("budget", t.number(), {
81
- default: 200000,
82
- description: "confirm before reading more than this many tokens"
83
- }).action((opts, { log, ps, clock }) => new Signoff(SIGNOFF_RULES, JUDGE_RULES.agent, {
84
- log,
85
- ps,
86
- clock
87
- }).run(opts));
53
+ description: "line-by-line output with no live progress block"
54
+ }).action((opts, deps) => judge(deps).judge(opts));
88
55
  var rules = webappwiz.group("rules").description("list and print the rules, to run or to read yourself");
89
56
  rules.command("ls").description("list the rules").action((_opts, deps) => judge(deps).ls());
90
57
  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/judge.d.ts CHANGED
@@ -1,11 +1,8 @@
1
- import { type Rule, type RuleSet } from "@webappwiz/rules";
1
+ import { type RuleSet } from "@webappwiz/rules";
2
2
  import { type Logger } from "webappwiz/log";
3
3
  import { type Fs, type Glob, type Ps } from "webappwiz/system";
4
4
  import { type Clock } from "webappwiz/time";
5
- /** Asked before a run spends more than it was allowed to. */
6
- export interface Confirm {
7
- confirm(question: string): boolean | Promise<boolean>;
8
- }
5
+ import { type Screen } from "./progress.js";
9
6
  export interface ShowOptions {
10
7
  /** The rule to print, as `rules ls` lists it. */
11
8
  id: string;
@@ -17,27 +14,19 @@ export interface JudgeOptions {
17
14
  exec?: string;
18
15
  /** Print the prompts to the logger and spawn nothing. */
19
16
  print?: boolean;
20
- /** Print what a run would read and stop. */
21
- estimate?: boolean;
22
17
  /** Files per review. */
23
18
  chunk: number;
24
19
  /** Narrows the run to what git says has changed since this ref. */
25
20
  since?: string;
26
- /** Tokens a run may read before it asks whether you meant it. */
27
- budget: number;
21
+ /** Agent calls in flight at once, over the config's `concurrency`. */
22
+ "concurrency-override"?: number;
23
+ /** Line-by-line output with no live block, the way a log wants it. */
24
+ ci?: boolean;
28
25
  }
29
- /**
30
- * Answers on the terminal, and answers no without one: a run nobody is watching
31
- * should stop and say the number rather than block forever waiting to be told
32
- * to go ahead.
33
- */
34
- export declare const ask: Confirm;
35
26
  /** What a `JudgeCommands` runs through, and what else it lists. */
36
27
  export interface JudgeCommandsOptions {
37
- /** Rules only a reader applies, listed beside the ones a run checks. */
38
- signoffRules?: Rule[];
39
- /** Who is asked before a run goes over budget; the terminal by default. */
40
- confirmer?: Confirm;
28
+ /** Where live progress draws; this process's terminal by default. */
29
+ screen?: Screen;
41
30
  log?: Logger;
42
31
  fs?: Fs;
43
32
  ps?: Ps;
@@ -46,24 +35,18 @@ export interface JudgeCommandsOptions {
46
35
  }
47
36
  export declare class JudgeCommands {
48
37
  private rules;
49
- private signoffRules;
50
- private confirmer;
38
+ private screen;
51
39
  private log;
52
40
  private fs;
53
41
  private ps;
54
42
  private clock;
55
43
  private glob;
56
44
  constructor(rules: RuleSet, opts?: JudgeCommandsOptions);
57
- /**
58
- * Lists every rule there is, one row each, ids first for citing. The rules a
59
- * run checks and the ones only a reader applies are one list with a SET
60
- * column, because "what rules are there" is one question.
61
- */
45
+ /** Lists every rule there is, one row each, ids first for citing. */
62
46
  ls(): void;
63
47
  /**
64
48
  * Prints one rule in full: what it covers, and the document an agent is
65
- * given, verbatim. Take the id from `rules ls` or from a finding. This is
66
- * how a reader applies a rule nothing runs for them.
49
+ * given, verbatim. Take the id from `rules ls` or from a finding.
67
50
  */
68
51
  show(opts: ShowOptions): void;
69
52
  /**
@@ -72,28 +55,9 @@ export declare class JudgeCommands {
72
55
  * it spawns nothing and prints the prompts instead, for an agent that would
73
56
  * rather hand them to subagents of its own.
74
57
  *
75
- * `since` narrows the run to what git says has changed, and `budget` caps
76
- * what it may read before asking whether you meant it. Under `estimate` it
77
- * prints that size and stops, which is the answer to "what would this cost"
78
- * without having to guess a budget low enough to be refused.
58
+ * `since` narrows the run to what git says has changed.
79
59
  */
80
60
  judge(opts: JudgeOptions): Promise<void>;
81
- /**
82
- * Measures what one call cost over the files it was handed and leaves that
83
- * behind, so the next `--estimate` on this agent has something better than a
84
- * floor. Per call rather than per token, because that is how the charge
85
- * falls: an agent pays for its own system prompt once per spawn, whatever it
86
- * was asked to read, so a figure taken from a two-call run still holds for a
87
- * fifteen-call one.
88
- *
89
- * A run nobody priced records nothing, and a failed write is said aloud
90
- * rather than thrown: the agents have already been paid for by this point,
91
- * and losing the measurement costs the next estimate accuracy, not the run.
92
- */
93
- private record;
94
61
  /** The agent a command runs with: what it was told, else the config's. */
95
62
  private agent;
96
- /** The model a run asks, or undefined for an `--exec` command, which is a
97
- * model nothing here can name or price. */
98
- private model;
99
63
  }
package/judge.js CHANGED
@@ -1,8 +1,6 @@
1
1
  import {
2
- JudgeCommands,
3
- ask
4
- } from "./index-jbrs6gqt.js";
2
+ JudgeCommands
3
+ } from "./index-pyjg1rtk.js";
5
4
  export {
6
- ask,
7
5
  JudgeCommands
8
6
  };
package/mode.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /** What a command does with the plan it has made. */
2
- export type Mode = "print" | "estimate" | "run";
3
- /** The flags that choose between the three, on top of the two that name an
2
+ export type Mode = "print" | "run";
3
+ /** The flags that choose between the two, on top of the two that name an
4
4
  * agent. */
5
5
  export interface ModeOptions {
6
6
  /** A model to ask. */
@@ -9,15 +9,13 @@ export interface ModeOptions {
9
9
  exec?: string;
10
10
  /** Print to the logger and spawn nothing. */
11
11
  print?: boolean;
12
- /** Print what a run would read, and spawn nothing. */
13
- estimate?: boolean;
14
12
  }
15
13
  /**
16
- * Which of the three a caller asked for, with running the default: a command
14
+ * Which of the two a caller asked for, with running the default: a command
17
15
  * given nothing but a directory is one somebody means to run.
18
16
  *
19
17
  * Naming two is an error rather than a quiet winner. All of these say what to
20
18
  * do with one plan, and letting one silently beat the other would leave a
21
19
  * caller unsure which of the two things they asked for they got.
22
20
  */
23
- export declare function mode({ print, estimate, agent, exec }: ModeOptions): Mode;
21
+ export declare function mode({ print, agent, exec }: ModeOptions): Mode;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@webappwiz/cli",
3
- "version": "0.0.7",
4
- "description": "The webappwiz CLI: judge code against rules, sign off a diff, and manage agent skills",
3
+ "version": "0.0.9",
4
+ "description": "The webappwiz CLI: judge code against rules and manage agent skills",
5
5
  "license": "MIT",
6
6
  "author": "Jared Johnson",
7
7
  "repository": {
@@ -17,8 +17,8 @@
17
17
  "access": "public"
18
18
  },
19
19
  "dependencies": {
20
- "@webappwiz/rules": "^0.0.7",
21
- "webappwiz": "^0.0.7"
20
+ "@webappwiz/rules": "^0.0.9",
21
+ "webappwiz": "^0.0.9"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "typescript": "^7"
@@ -41,10 +41,6 @@
41
41
  "./judge": {
42
42
  "types": "./judge.d.ts",
43
43
  "default": "./judge.js"
44
- },
45
- "./signoff": {
46
- "types": "./signoff.d.ts",
47
- "default": "./signoff.js"
48
44
  }
49
45
  },
50
46
  "bin": {