@webappwiz/cli 0.0.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/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@webappwiz/cli",
3
+ "version": "0.0.1",
4
+ "description": "The webappwiz CLI: judge code against rules, sign off a diff, and manage agent skills",
5
+ "license": "MIT",
6
+ "author": "Jared Johnson",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/jaredjj3/webappwiz.git",
10
+ "directory": "packages/cli"
11
+ },
12
+ "type": "module",
13
+ "engines": {
14
+ "bun": ">=1.3"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "dependencies": {
20
+ "@webappwiz/rules": "^0.0.1",
21
+ "webappwiz": "^0.0.1"
22
+ },
23
+ "peerDependencies": {
24
+ "typescript": "^7"
25
+ },
26
+ "main": "./index.js",
27
+ "types": "./index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./index.d.ts",
31
+ "default": "./index.js"
32
+ },
33
+ "./webappwiz": {
34
+ "types": "./webappwiz.d.ts",
35
+ "default": "./webappwiz.js"
36
+ },
37
+ "./rules": {
38
+ "types": "./rules.d.ts",
39
+ "default": "./rules.js"
40
+ },
41
+ "./judge": {
42
+ "types": "./judge.d.ts",
43
+ "default": "./judge.js"
44
+ },
45
+ "./signoff": {
46
+ "types": "./signoff.d.ts",
47
+ "default": "./signoff.js"
48
+ }
49
+ },
50
+ "bin": {
51
+ "webappwiz": "./index.js"
52
+ }
53
+ }
package/report.d.ts ADDED
@@ -0,0 +1,85 @@
1
+ import type { Violation } from "@webappwiz/rules";
2
+ import type { Duration } from "webappwiz/time";
3
+ import { type Overheads } from "./cost.js";
4
+ export declare const count: (total: number, word: string) => string;
5
+ /**
6
+ * Where one printed document stops and the next starts, named so a reader
7
+ * knows which one they are in without scrolling back.
8
+ *
9
+ * What `--print` writes is pages of markdown with headings of its own, so a
10
+ * heading is not enough to mark a boundary. Unnamed, this is the closing line
11
+ * the last document wants as much as the others want an opening one.
12
+ */
13
+ export declare const divider: (name?: string) => string;
14
+ export declare const usd: (amount: number) => string;
15
+ /**
16
+ * What a plan costs to read, at the four-bytes-a-token rule of thumb. Rough on
17
+ * purpose: an estimate that needed a tokenizer, or an API call to count, would
18
+ * be one more thing to install and one more thing to be wrong about, and the
19
+ * decision it informs is only ever "is this the order of magnitude I meant".
20
+ */
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
+ /**
40
+ * The plan, before the first agent starts. Counts calls rather than reviews
41
+ * because a call is what a run is billed for, and it is the denominator of the
42
+ * `[n/total]` headings below. Without an `agent` it is the whole of what
43
+ * `--estimate` prints, so it names no command it is not going to run.
44
+ */
45
+ export interface Planned {
46
+ files: number;
47
+ rules: number;
48
+ calls: number;
49
+ /** Tokens the plan can see, which is a floor on what the run reads. */
50
+ estimate: number;
51
+ /** Agent calls in flight at once, which is what the wall clock turns on. */
52
+ concurrency?: number;
53
+ /** What those calls are predicted to cost, when the agent has a price. */
54
+ cost?: number;
55
+ /** The command the run will spawn. */
56
+ agent?: string;
57
+ }
58
+ export declare function planned({ files, rules, calls, estimate, concurrency, cost, agent, }: Planned): string[];
59
+ /** A finished review as the report prints it: what the call covered, what it
60
+ * found, and what it cost. */
61
+ export interface Finished {
62
+ /** The ids of the rules the review checked. */
63
+ rules: string[];
64
+ /** How many files this review's agent was told to read. */
65
+ files: number;
66
+ violations: Violation[];
67
+ /** How long this review's agent took. */
68
+ took: Duration;
69
+ /** Dollars this review's call was billed, when the agent reported a figure. */
70
+ cost?: number;
71
+ done: number;
72
+ total: number;
73
+ }
74
+ /**
75
+ * A finished review, as it should print the moment its agent returns: a status
76
+ * line sizing the call, then one finding per violation.
77
+ */
78
+ export declare function finished({ rules, files, violations, took, cost, done, total, }: Finished): string[];
79
+ /**
80
+ * One violation: a location a reader can click, what the code does that the
81
+ * rule forbids, and the line it happens on. The heading above names only the
82
+ * glob, so the finding says which of its rules this one breaks.
83
+ */
84
+ export declare function finding(violation: Violation): string[];
85
+ export declare function summary(violations: Violation[], took: Duration, cost?: number): string;
package/rules.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { type Rule } from "@webappwiz/rules";
2
+ /**
3
+ * Every rule webappwiz judges itself by, named one by one. There is no preset
4
+ * to spread and nothing runs implicitly: a rule is here or it does not run.
5
+ *
6
+ * A constant rather than a config file, because rules reach the harness as
7
+ * objects. A project with its own rules writes its own list and hands it to
8
+ * `JudgeCommands` or to `Check` directly, rather than pointing a flag at a
9
+ * module for one of these to import.
10
+ */
11
+ 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 ADDED
@@ -0,0 +1,8 @@
1
+ import {
2
+ JUDGE_RULES,
3
+ SIGNOFF_RULES
4
+ } from "./index-8jpb8xae.js";
5
+ export {
6
+ SIGNOFF_RULES,
7
+ JUDGE_RULES
8
+ };
package/signoff.d.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { type Rule } from "@webappwiz/rules";
2
+ import { type Logger } from "webappwiz/log";
3
+ import { type Ps } from "webappwiz/system";
4
+ import { type Clock } from "webappwiz/time";
5
+ import { type Confirm } from "./judge.js";
6
+ export interface SignoffRunOptions {
7
+ /** The directory whose change is being weighed. */
8
+ dir: string;
9
+ agent?: string;
10
+ exec?: string;
11
+ /** Print the rules to the logger and spawn nothing, for the reader who is
12
+ * going to apply them itself. */
13
+ print?: boolean;
14
+ /** The ref the change is measured against: everything since it is the
15
+ * change. */
16
+ since: string;
17
+ /** Tokens a run may read before it asks whether you meant it. */
18
+ budget: number;
19
+ }
20
+ /**
21
+ * Weighs a change against the rules that decide whether it can merge on its
22
+ * own or needs a person to look at it first.
23
+ *
24
+ * One agent call over the diff, rather than one per file like `judge`: these
25
+ * rules are about the change as a whole, and a run that saw one file at a time
26
+ * could not answer them. Exits 1 with a reason when the change needs a person,
27
+ * so it reads the same to a merge gate as to whoever ran it.
28
+ */
29
+ /** What a `Signoff` runs through. */
30
+ export interface SignoffOptions {
31
+ /** Who is asked before a run goes over budget; the terminal by default. */
32
+ confirmer?: Confirm;
33
+ log?: Logger;
34
+ ps?: Ps;
35
+ clock?: Clock;
36
+ }
37
+ export declare class Signoff {
38
+ private rules;
39
+ private defaultAgent;
40
+ private confirmer;
41
+ private log;
42
+ private ps;
43
+ private clock;
44
+ constructor(rules: Rule[], defaultAgent: string, opts?: SignoffOptions);
45
+ run(opts: SignoffRunOptions): Promise<void>;
46
+ /** The one call, and what it says about the change. */
47
+ private judge;
48
+ /**
49
+ * The verdict, and a reason for each rule that wants a person. Throws on any
50
+ * of them: an agent that ran this before merging should escalate rather than
51
+ * merge, and an exit code is what says so whoever is reading.
52
+ */
53
+ private say;
54
+ /** The change as the agent reads it, priced by the prompt: what a new file
55
+ * costs to open is the agent's business and unknowable from here. */
56
+ private review;
57
+ /**
58
+ * The rules in full, for the reader who is going to apply them. Nothing has
59
+ * to run these: an agent about to merge its own work can weigh it against
60
+ * them itself, and that is the cheapest signoff there is.
61
+ */
62
+ private print;
63
+ }
package/signoff.js ADDED
@@ -0,0 +1,7 @@
1
+ import {
2
+ Signoff
3
+ } from "./index-3k3rtw49.js";
4
+ import"./index-jbrs6gqt.js";
5
+ export {
6
+ Signoff
7
+ };
@@ -0,0 +1,7 @@
1
+ import { type ProjectOptions } from "./skill.js";
2
+ export interface AddOptions extends ProjectOptions {
3
+ /** The skill to install, as `skills ls` names it. */
4
+ skill: string;
5
+ }
6
+ /** Adds a skill a project does not have yet. */
7
+ export declare function add(opts: AddOptions): Promise<void>;
package/skills/ls.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { type ProjectOptions } from "./skill.js";
2
+ /**
3
+ * What there is to install, and what the project has of it. The version a
4
+ * project holds is the only thing `add` and `update` cannot tell it, so that
5
+ * is what this is for.
6
+ */
7
+ export declare function ls(opts: ProjectOptions): Promise<void>;
@@ -0,0 +1,36 @@
1
+ import type { Logger } from "webappwiz/log";
2
+ import type { Fs } from "webappwiz/system";
3
+ /** Skill name to the document a project installs under that name. */
4
+ export type Skills = Record<string, string>;
5
+ /**
6
+ * The skills this package ships.
7
+ *
8
+ * They are imported rather than read out of a directory so they travel inside
9
+ * the build: what publishes is the compiled JavaScript, and a document sitting
10
+ * beside the source would not be part of it. Naming each one also means adding
11
+ * a skill is a line here rather than a file that a directory listing may or may
12
+ * not happen to pick up.
13
+ */
14
+ export declare const bundled: Skills;
15
+ export declare function versionOf(md: string): string | null;
16
+ /** The project a skills command works on. */
17
+ export interface ProjectOptions {
18
+ /** Its root: the directory holding `.agents/skills`. */
19
+ dir: string;
20
+ log?: Logger;
21
+ fs?: Fs;
22
+ /** The skills on offer; the ones this package ships by default. */
23
+ skills?: Skills;
24
+ }
25
+ /**
26
+ * Every skill on offer, name and document together, in the order they are
27
+ * listed and installed in.
28
+ */
29
+ export declare function available(skills: Skills): Array<[string, string]>;
30
+ /** What `copy` works through, once an action has resolved them. */
31
+ export interface CopyOptions {
32
+ log: Logger;
33
+ fs: Fs;
34
+ }
35
+ /** Installs one skill into a project. */
36
+ export declare function copy(name: string, doc: string, dir: string, opts: CopyOptions): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import { type ProjectOptions } from "./skill.js";
2
+ /**
3
+ * Refreshes the skills a project already has. Which skills those are is the
4
+ * project's business, so this never adds one: a skill someone chose not to
5
+ * install should not arrive by way of an update.
6
+ */
7
+ export declare function update(opts: ProjectOptions): Promise<void>;
package/table.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Row one is the header. Columns line up by what a cell shows rather than by
3
+ * what it holds, since a colored cell carries escapes nobody sees.
4
+ */
5
+ export declare const table: (rows: string[][]) => string[];
package/update.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { type Logger } from "webappwiz/log";
2
+ import { type Fs } from "webappwiz/system";
3
+ import type { Skills } from "./skills/skill.js";
4
+ /** Which tree to pin, and to what. */
5
+ export interface UpdateOptions {
6
+ /** The directory to scan recursively for manifests. */
7
+ dir: string;
8
+ /** The version every webappwiz entry is set to. */
9
+ version: string;
10
+ log?: Logger;
11
+ fs?: Fs;
12
+ /** The skills to refresh with; the ones this package ships by default. */
13
+ skills?: Skills;
14
+ }
15
+ /**
16
+ * Pins every webappwiz dependency under `dir` to one version, so a project
17
+ * never runs two of these packages built against different versions of each
18
+ * other. They are released together, so there is only ever one right answer.
19
+ * Installed skills are copies of files those packages ship, so they are
20
+ * refreshed too.
21
+ */
22
+ export declare function update(opts: UpdateOptions): Promise<void>;
package/webappwiz.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { type Deps } from "webappwiz/cmd";
2
+ import type { Fs, Glob } from "webappwiz/system";
3
+ import type { Clock } from "webappwiz/time";
4
+ /** What webappwiz's commands are run with, on top of what any cli needs. */
5
+ export interface CommandDeps extends Deps {
6
+ fs: Fs;
7
+ clock: Clock;
8
+ glob: Glob;
9
+ }
10
+ /**
11
+ * The `webappwiz` program. Run on its own it is the `webappwiz` bin; mounted
12
+ * (`wiz.mount("cli", webappwiz)`) the same commands answer as `wiz cli`, so
13
+ * neither spelling shells out to the other.
14
+ */
15
+ export declare const webappwiz: import("webappwiz/cmd").Cli<CommandDeps, CommandDeps>;
package/webappwiz.js ADDED
@@ -0,0 +1,100 @@
1
+ import {
2
+ add,
3
+ ls,
4
+ update,
5
+ update1 as update2,
6
+ version
7
+ } from "./index-g2q5rg7s.js";
8
+ import {
9
+ JUDGE_RULES,
10
+ SIGNOFF_RULES
11
+ } from "./index-8jpb8xae.js";
12
+ import {
13
+ Signoff
14
+ } from "./index-3k3rtw49.js";
15
+ import {
16
+ JudgeCommands
17
+ } from "./index-jbrs6gqt.js";
18
+
19
+ // webappwiz.ts
20
+ import { AGENTS } from "@webappwiz/rules";
21
+ import { cli } from "webappwiz/cmd";
22
+ import { t } from "webappwiz/t";
23
+ var webappwiz = cli("webappwiz");
24
+ webappwiz.command("update").description("pin every webappwiz dependency in a tree to one version").arg("dir", t.string(), {
25
+ default: ".",
26
+ description: "directory to scan recursively (default: .)"
27
+ }).option("version", t.string(), {
28
+ default: version,
29
+ description: "version to pin to"
30
+ }).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
+ });
39
+ webappwiz.command("judge").description("check a directory against the config, one agent per glob").arg("dir", t.string(), {
40
+ default: ".",
41
+ description: "directory to judge (default: .)"
42
+ }).option("agent", t.optional(t.enum(Object.keys(AGENTS))), {
43
+ description: "model to check with (default: the config's agent)"
44
+ }).option("exec", t.optional(t.string()), {
45
+ description: "command the prompt is passed to, instead of --agent"
46
+ }).option("print", t.boolean(), {
47
+ default: false,
48
+ 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
+ }).option("chunk", t.number(), {
53
+ default: 25,
54
+ description: "files per review"
55
+ }).option("since", t.optional(t.string()), {
56
+ description: "only check files added or changed since this git ref"
57
+ }).option("budget", t.number(), {
58
+ default: 200000,
59
+ description: "confirm before reading more than this many tokens"
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(), {
69
+ default: false,
70
+ description: "print the rules to apply yourself, and run no agent"
71
+ }).option("since", t.string(), {
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));
82
+ var rules = webappwiz.group("rules").description("list and print the rules, to run or to read yourself");
83
+ rules.command("ls").description("list the rules").action((_opts, deps) => judge(deps).ls());
84
+ 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));
85
+ var skillsGroup = webappwiz.group("skills").description("manage webappwiz agent skills in .agents/skills");
86
+ skillsGroup.command("ls").description("list the skills there are, and what the project has of them").arg("dir", t.string(), {
87
+ default: ".",
88
+ description: "project to inspect (default: .)"
89
+ }).action((opts, { log, fs }) => ls({ ...opts, log, fs }));
90
+ skillsGroup.command("add").description("add a skill to a project").arg("skill", t.string(), { description: "skill name" }).arg("dir", t.string(), {
91
+ default: ".",
92
+ description: "project to add it to (default: .)"
93
+ }).action((opts, { log, fs }) => add({ ...opts, log, fs }));
94
+ skillsGroup.command("update").description("refresh the skills a project already has").arg("dir", t.string(), {
95
+ default: ".",
96
+ description: "project to refresh (default: .)"
97
+ }).action((opts, { log, fs }) => update({ ...opts, log, fs }));
98
+ export {
99
+ webappwiz
100
+ };