@coldtea/pr-lens-cli 0.1.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.
- package/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/args.d.ts +18 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +49 -0
- package/dist/args.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +8 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +97 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/analyze.d.ts +4 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +158 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/comment.d.ts +4 -0
- package/dist/commands/comment.d.ts.map +1 -0
- package/dist/commands/comment.js +63 -0
- package/dist/commands/comment.js.map +1 -0
- package/dist/commands/export.d.ts +4 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +44 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/render.d.ts +4 -0
- package/dist/commands/render.d.ts.map +1 -0
- package/dist/commands/render.js +108 -0
- package/dist/commands/render.js.map +1 -0
- package/dist/commands/validate.d.ts +4 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +49 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/comment.d.ts +16 -0
- package/dist/comment.d.ts.map +1 -0
- package/dist/comment.js +148 -0
- package/dist/comment.js.map +1 -0
- package/dist/config-file.d.ts +10 -0
- package/dist/config-file.d.ts.map +1 -0
- package/dist/config-file.js +19 -0
- package/dist/config-file.js.map +1 -0
- package/dist/corrections.d.ts +16 -0
- package/dist/corrections.d.ts.map +1 -0
- package/dist/corrections.js +80 -0
- package/dist/corrections.js.map +1 -0
- package/dist/document.d.ts +23 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +75 -0
- package/dist/document.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +14 -0
- package/dist/errors.js.map +1 -0
- package/dist/extract.d.ts +54 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +84 -0
- package/dist/extract.js.map +1 -0
- package/dist/git.d.ts +40 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +104 -0
- package/dist/git.js.map +1 -0
- package/dist/io.d.ts +6 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +35 -0
- package/dist/io.js.map +1 -0
- package/dist/prompt.d.ts +23 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +69 -0
- package/dist/prompt.js.map +1 -0
- package/dist/providers/gemini.d.ts +3 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +46 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/http.d.ts +5 -0
- package/dist/providers/http.d.ts.map +1 -0
- package/dist/providers/http.js +26 -0
- package/dist/providers/http.js.map +1 -0
- package/dist/providers/index.d.ts +48 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +71 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +17 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +42 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/snapshot.d.ts +15 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +77 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/terminal.d.ts +6 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +5 -0
- package/dist/terminal.js.map +1 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/package.json +57 -0
- package/src/args.ts +52 -0
- package/src/bin.ts +10 -0
- package/src/cli.ts +120 -0
- package/src/commands/analyze.ts +206 -0
- package/src/commands/comment.ts +77 -0
- package/src/commands/export.ts +61 -0
- package/src/commands/render.ts +125 -0
- package/src/commands/validate.ts +57 -0
- package/src/comment.ts +190 -0
- package/src/config-file.ts +26 -0
- package/src/corrections.ts +86 -0
- package/src/document.ts +119 -0
- package/src/errors.ts +36 -0
- package/src/extract.ts +136 -0
- package/src/git.ts +151 -0
- package/src/io.ts +38 -0
- package/src/prompt.ts +87 -0
- package/src/providers/gemini.ts +61 -0
- package/src/providers/http.ts +54 -0
- package/src/providers/index.ts +124 -0
- package/src/providers/openai.ts +68 -0
- package/src/snapshot.ts +102 -0
- package/src/terminal.ts +9 -0
- package/src/version.ts +4 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ohans Emmanuel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# @coldtea/pr-lens-cli
|
|
2
|
+
|
|
3
|
+
PR Lens on the command line. It reads a diff with your own model key, checks the result against the contract, and hands you the pull request comment.
|
|
4
|
+
|
|
5
|
+
MIT © Ohans Emmanuel.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @coldtea/pr-lens-cli analyze --base origin/main
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Bring your own key
|
|
12
|
+
|
|
13
|
+
The key is read from the environment, never from a flag: a flag lands in shell history and in the log of whatever CI runs it. The diff goes to the provider you name and nowhere else — there is no PR Lens service in this path.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
export GEMINI_API_KEY=…
|
|
17
|
+
pr-lens analyze --base origin/main --head HEAD
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Three request shapes are implemented rather than a list of vendors:
|
|
21
|
+
|
|
22
|
+
| `--provider` | Endpoint | Key |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `gemini` (default) | Google's own API | `GEMINI_API_KEY` |
|
|
25
|
+
| `openai` | OpenAI's own API | `OPENAI_API_KEY` |
|
|
26
|
+
| `openai-compatible` | anything else speaking `/chat/completions`, named by `--base-url` | `OPENAI_API_KEY` |
|
|
27
|
+
|
|
28
|
+
DeepSeek, Anthropic's compatibility endpoint, OpenRouter, Ollama and llama.cpp are all reached by pointing `--base-url` at them, and a new vendor needs no release here. OpenAI is listed separately from the servers that copied it because the two have drifted: it renamed the output limit to `max_completion_tokens` and its newer models reject `max_tokens`, which is the only spelling the others know. There is no field both accept, so you say which endpoint you are talking to rather than the CLI guessing from a hostname.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pr-lens analyze --base origin/main \
|
|
32
|
+
--provider openai-compatible \
|
|
33
|
+
--base-url http://localhost:11434/v1 \
|
|
34
|
+
--model qwen3-coder \
|
|
35
|
+
--api-key-env OLLAMA_KEY
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## The commands
|
|
39
|
+
|
|
40
|
+
### `analyze`
|
|
41
|
+
|
|
42
|
+
Diff in, graph document out.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pr-lens analyze --base origin/main --pr 42 -o pr-lens/graph.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The base is the merge base of the two refs, not the tip of the base branch: a diff against the tip would blame this pull request for every change made on the base branch since it forked.
|
|
49
|
+
|
|
50
|
+
The commit shas, the repository, the pull request number and the line counts are filled in from the repository itself, and anything the model writes there is discarded. A fact the model is free to restate is a fact that eventually disagrees with itself.
|
|
51
|
+
|
|
52
|
+
The answer is parsed against the contract. If it fails, the validation errors — paths and all — go back to the model once, and only once: a model that cannot fix a named path in one round does not fix it in three. `--dry-run` reports what would be sent and sends nothing.
|
|
53
|
+
|
|
54
|
+
### `render`
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pr-lens render pr-lens/graph.json -o pr-lens/
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Draws the document as self-contained light and dark SVGs — one pair per drill-down section per lens, or one pair per lens when the document has no sections — and writes two files beside them: `manifest.json`, which says what was drawn and under which file name, and `drawn.graph.json`, the document those pictures actually show.
|
|
61
|
+
|
|
62
|
+
Both matter to what comes next. The manifest is where `comment` gets its file names, so neither command re-derives the other's. And `drawn.graph.json` exists because this is where corrections are applied: excluding a node can empty out a whole drill-down section, and the renderer then draws no picture for it. A comment composed from the document that went *in* would announce a section that came out of nothing.
|
|
63
|
+
|
|
64
|
+
The SVGs carry no script and no external reference, and the same document renders to the same bytes every time. `--theme light` or `--theme dark` draws one half of the pair.
|
|
65
|
+
|
|
66
|
+
### `comment`
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pr-lens comment --graph pr-lens/drawn.graph.json --manifest pr-lens/manifest.json \
|
|
70
|
+
--asset-base-url https://raw.githubusercontent.com/owner/repo/pr-lens/42
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Composes the markdown — the `<picture>` pairs that read in both GitHub themes, the headline chips, the nested `<details>` tree — and prints it. Each diagram links to itself: a comment column is about 830 pixels wide and a system with several lanes is several times that, so it arrives scaled to fit and one click gives a reader the size the labels were drawn at. The two files have to belong to each other: the manifest records the hash of the document it came from, and a mismatched pair is refused rather than composed into a comment describing diagrams nobody drew. It posts nothing; posting is the caller's business, and `--print-marker` gives that caller the hidden marker that identifies an existing comment to update.
|
|
74
|
+
|
|
75
|
+
### `validate`
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pr-lens validate pr-lens/graph.json .github/pr-lens.yml
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Parses graph documents, patch documents, render manifests and configs, JSON or YAML, and reports every problem in each rather than only the first. A file with no `kind` field is read as a config, because a config is the only one of the four a person writes by hand.
|
|
82
|
+
|
|
83
|
+
### `export`
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pr-lens export pr-lens/graph.json -o .github/pr-lens.map.json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Turns a pull-request document into the map of the system once that pull request has merged: elements the change deletes are dropped — with the edges and flow steps that hung from them — the rest stops being annotated, and the result is stamped with the single commit it reflects.
|
|
90
|
+
|
|
91
|
+
The map is a snapshot, not a source of truth. Nothing reads it back into the pipeline: a committed map that overrode inference would be hand-maintained rot with merge conflicts attached. Commit it so a repository has something to read, to diff, and to hand an agent.
|
|
92
|
+
|
|
93
|
+
## Corrections
|
|
94
|
+
|
|
95
|
+
A repository's `.github/pr-lens.yml` is picked up automatically by `render` and applied at draw time — renames, exclusions, lane pins, groupings. It is an overlay: inference never writes back into it, so a correction keeps holding as the code moves and the model renames things between runs, and the document on disk stays the record of what was inferred.
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
schemaVersion: 0.1.0
|
|
99
|
+
map:
|
|
100
|
+
rename:
|
|
101
|
+
- match: functions/src/broadcast/sendBroadcastBulk.ts
|
|
102
|
+
to: Broadcast sender
|
|
103
|
+
exclude:
|
|
104
|
+
- "**/*.test.ts"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A lane pin may name a lane the document never declared; the band is created and takes the id for its label. And `render` reports any correction that changed nothing about what it drew — a config that has drifted, usually because the file a selector named has moved, otherwise fails silently and forever.
|
|
108
|
+
|
|
109
|
+
`--config` points elsewhere and `--no-config` ignores it, on both `render` and `analyze` — `analyze` reads only `lenses` from it, since which lenses to fill is a question for extraction and the rest is a question for drawing.
|
|
110
|
+
|
|
111
|
+
## Failures
|
|
112
|
+
|
|
113
|
+
Every failure carries a code, so a script can branch on it: `USAGE`, `UNREADABLE_FILE`, `UNKNOWN_DOCUMENT`, `INVALID_DOCUMENT`, `GIT_FAILED`, `EMPTY_DIFF`, `REPOSITORY_UNKNOWN`, `MISSING_API_KEY`, `PROVIDER_FAILED`, `MODEL_OUTPUT_INVALID`, `RENDER_FAILED`. Misuse exits 2, everything else exits 1.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
Part of [PR Lens](https://prlens.dev) — review what actually matters.
|
package/dist/args.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ParseArgsConfig } from "node:util";
|
|
2
|
+
type Options = NonNullable<ParseArgsConfig["options"]>;
|
|
3
|
+
/**
|
|
4
|
+
* `parseArgs` throws a plain `TypeError` on an unknown flag or a missing
|
|
5
|
+
* value, which would surface as a stack trace. Every one of them is a usage
|
|
6
|
+
* mistake and reads as one.
|
|
7
|
+
*/
|
|
8
|
+
export declare const parseOptions: <Config extends Options>(args: readonly string[], options: Config) => {
|
|
9
|
+
values: Record<string, string | boolean | string[] | undefined>;
|
|
10
|
+
positionals: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare const readString: (value: unknown, flag: string) => string | undefined;
|
|
13
|
+
export declare const readBoolean: (value: unknown) => boolean;
|
|
14
|
+
export declare const readInt: (value: unknown, flag: string, fallback: number) => number;
|
|
15
|
+
export declare const readList: (value: unknown, flag: string) => string[] | undefined;
|
|
16
|
+
export declare const expectOne: (positionals: readonly string[], what: string) => string;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5D,KAAK,OAAO,GAAG,WAAW,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,SAAS,OAAO,QAC3C,SAAS,MAAM,EAAE,WACd,MAAM,KACd;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAO1F,CAAC;AAEF,eAAO,MAAM,UAAU,UAAW,OAAO,QAAQ,MAAM,KAAG,MAAM,GAAG,SAIlE,CAAC;AAEF,eAAO,MAAM,WAAW,UAAW,OAAO,KAAG,OAAyB,CAAC;AAEvE,eAAO,MAAM,OAAO,UAAW,OAAO,QAAQ,MAAM,YAAY,MAAM,KAAG,MAQxE,CAAC;AAEF,eAAO,MAAM,QAAQ,UAAW,OAAO,QAAQ,MAAM,KAAG,MAAM,EAAE,GAAG,SAIlE,CAAC;AAEF,eAAO,MAAM,SAAS,gBAAiB,SAAS,MAAM,EAAE,QAAQ,MAAM,KAAG,MAKxE,CAAC"}
|
package/dist/args.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import { usageError } from "./errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* `parseArgs` throws a plain `TypeError` on an unknown flag or a missing
|
|
5
|
+
* value, which would surface as a stack trace. Every one of them is a usage
|
|
6
|
+
* mistake and reads as one.
|
|
7
|
+
*/
|
|
8
|
+
export const parseOptions = (args, options) => {
|
|
9
|
+
try {
|
|
10
|
+
const parsed = parseArgs({ args: [...args], options, allowPositionals: true, strict: true });
|
|
11
|
+
return { values: parsed.values, positionals: parsed.positionals };
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
throw usageError(error instanceof Error ? error.message : String(error));
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export const readString = (value, flag) => {
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
if (typeof value !== "string")
|
|
21
|
+
throw usageError(`--${flag} needs a value`);
|
|
22
|
+
return value;
|
|
23
|
+
};
|
|
24
|
+
export const readBoolean = (value) => value === true;
|
|
25
|
+
export const readInt = (value, flag, fallback) => {
|
|
26
|
+
const text = readString(value, flag);
|
|
27
|
+
if (text === undefined)
|
|
28
|
+
return fallback;
|
|
29
|
+
const parsed = Number(text);
|
|
30
|
+
if (!Number.isInteger(parsed) || parsed <= 0)
|
|
31
|
+
throw usageError(`--${flag} needs a positive whole number, got ${JSON.stringify(text)}`);
|
|
32
|
+
return parsed;
|
|
33
|
+
};
|
|
34
|
+
export const readList = (value, flag) => {
|
|
35
|
+
if (value === undefined)
|
|
36
|
+
return undefined;
|
|
37
|
+
if (!Array.isArray(value))
|
|
38
|
+
throw usageError(`--${flag} needs a value`);
|
|
39
|
+
return value.flatMap((entry) => (typeof entry === "string" ? entry.split(",") : []));
|
|
40
|
+
};
|
|
41
|
+
export const expectOne = (positionals, what) => {
|
|
42
|
+
const [first, ...rest] = positionals;
|
|
43
|
+
if (first === undefined)
|
|
44
|
+
throw usageError(`expected ${what}`);
|
|
45
|
+
if (rest.length > 0)
|
|
46
|
+
throw usageError(`expected ${what}, got ${positionals.length} arguments`);
|
|
47
|
+
return first;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=args.js.map
|
package/dist/args.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAwB,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,IAAuB,EACvB,OAAe,EAC6E,EAAE;IAC9F,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,UAAU,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAc,EAAE,IAAY,EAAsB,EAAE;IAC7E,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,UAAU,CAAC,KAAK,IAAI,gBAAgB,CAAC,CAAC;IAC3E,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAc,EAAW,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC;AAEvE,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,IAAY,EAAE,QAAgB,EAAU,EAAE;IAChF,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAExC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC;QAC1C,MAAM,UAAU,CAAC,KAAK,IAAI,uCAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3F,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAE,IAAY,EAAwB,EAAE;IAC7E,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,UAAU,CAAC,KAAK,IAAI,gBAAgB,CAAC,CAAC;IACvE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,WAA8B,EAAE,IAAY,EAAU,EAAE;IAChF,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,WAAW,CAAC;IACrC,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,UAAU,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC9D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,UAAU,CAAC,YAAY,IAAI,SAAS,WAAW,CAAC,MAAM,YAAY,CAAC,CAAC;IAC/F,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { run } from "./cli.js";
|
|
3
|
+
import { processTerminal } from "./terminal.js";
|
|
4
|
+
process.exitCode = await run(process.argv.slice(2), processTerminal, process.env).catch((error) => {
|
|
5
|
+
processTerminal.err(error instanceof Error ? (error.stack ?? error.message) : String(error));
|
|
6
|
+
return 1;
|
|
7
|
+
});
|
|
8
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CACrF,CAAC,KAAc,EAAE,EAAE;IACjB,eAAe,CAAC,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7F,OAAO,CAAC,CAAC;AACX,CAAC,CACF,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAkE9C,eAAO,MAAM,GAAG,SACR,SAAS,MAAM,EAAE,YACb,QAAQ,OACb,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KACtC,OAAO,CAAC,MAAM,CA0ChB,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { assertNever } from "@coldtea/pr-lens-schema";
|
|
2
|
+
import { analyzeCommand, USAGE as ANALYZE_USAGE } from "./commands/analyze.js";
|
|
3
|
+
import { commentCommand, USAGE as COMMENT_USAGE } from "./commands/comment.js";
|
|
4
|
+
import { exportCommand, USAGE as EXPORT_USAGE } from "./commands/export.js";
|
|
5
|
+
import { renderCommand, USAGE as RENDER_USAGE } from "./commands/render.js";
|
|
6
|
+
import { USAGE as VALIDATE_USAGE, validateCommand } from "./commands/validate.js";
|
|
7
|
+
import { formatError, PrLensCliError } from "./errors.js";
|
|
8
|
+
import { CLI_VERSION } from "./version.js";
|
|
9
|
+
const COMMANDS = ["analyze", "render", "comment", "validate", "export"];
|
|
10
|
+
const isCommand = (value) => COMMANDS.some((command) => command === value);
|
|
11
|
+
const HELP = `pr-lens — review what actually matters
|
|
12
|
+
|
|
13
|
+
pr-lens analyze --base <ref> a diff, read by your own model, as a graph document
|
|
14
|
+
pr-lens render <graph.json> that document, as light and dark SVGs
|
|
15
|
+
pr-lens comment --graph --manifest the pull request comment, as markdown
|
|
16
|
+
pr-lens validate <file...> any PR Lens document, checked against the contract
|
|
17
|
+
pr-lens export <graph.json> the merged state, as a map worth committing
|
|
18
|
+
|
|
19
|
+
pr-lens <command> --help what a command takes
|
|
20
|
+
pr-lens --version
|
|
21
|
+
|
|
22
|
+
Your model key is read from the environment and goes only to the provider you
|
|
23
|
+
name. https://github.com/coldteadotai/pr-lens`;
|
|
24
|
+
const usageFor = (command) => {
|
|
25
|
+
switch (command) {
|
|
26
|
+
case "analyze":
|
|
27
|
+
return ANALYZE_USAGE;
|
|
28
|
+
case "render":
|
|
29
|
+
return RENDER_USAGE;
|
|
30
|
+
case "comment":
|
|
31
|
+
return COMMENT_USAGE;
|
|
32
|
+
case "validate":
|
|
33
|
+
return VALIDATE_USAGE;
|
|
34
|
+
case "export":
|
|
35
|
+
return EXPORT_USAGE;
|
|
36
|
+
default:
|
|
37
|
+
return assertNever(command, "Unhandled command");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const dispatch = (command, args, terminal, env) => {
|
|
41
|
+
switch (command) {
|
|
42
|
+
case "analyze":
|
|
43
|
+
return analyzeCommand(args, terminal, env);
|
|
44
|
+
case "render":
|
|
45
|
+
return renderCommand(args, terminal);
|
|
46
|
+
case "comment":
|
|
47
|
+
return commentCommand(args, terminal);
|
|
48
|
+
case "validate":
|
|
49
|
+
return validateCommand(args, terminal);
|
|
50
|
+
case "export":
|
|
51
|
+
return exportCommand(args, terminal);
|
|
52
|
+
default:
|
|
53
|
+
return assertNever(command, "Unhandled command");
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const EXIT_OK = 0;
|
|
57
|
+
const EXIT_FAILED = 1;
|
|
58
|
+
const EXIT_MISUSED = 2;
|
|
59
|
+
export const run = async (argv, terminal, env) => {
|
|
60
|
+
const [name, ...args] = argv;
|
|
61
|
+
if (name === undefined) {
|
|
62
|
+
terminal.err(HELP);
|
|
63
|
+
return EXIT_MISUSED;
|
|
64
|
+
}
|
|
65
|
+
if (name === "--help" || name === "-h" || name === "help") {
|
|
66
|
+
terminal.out(HELP);
|
|
67
|
+
return EXIT_OK;
|
|
68
|
+
}
|
|
69
|
+
if (name === "--version" || name === "-v") {
|
|
70
|
+
terminal.out(CLI_VERSION);
|
|
71
|
+
return EXIT_OK;
|
|
72
|
+
}
|
|
73
|
+
if (!isCommand(name)) {
|
|
74
|
+
terminal.err(formatError(new PrLensCliError("USAGE", `unknown command ${JSON.stringify(name)}`)));
|
|
75
|
+
terminal.err(HELP);
|
|
76
|
+
return EXIT_MISUSED;
|
|
77
|
+
}
|
|
78
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
79
|
+
terminal.out(usageFor(name));
|
|
80
|
+
return EXIT_OK;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
await dispatch(name, args, terminal, env);
|
|
84
|
+
return EXIT_OK;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (!(error instanceof PrLensCliError))
|
|
88
|
+
throw error;
|
|
89
|
+
terminal.err(formatError(error));
|
|
90
|
+
if (error.code !== "USAGE")
|
|
91
|
+
return EXIT_FAILED;
|
|
92
|
+
terminal.err("");
|
|
93
|
+
terminal.err(usageFor(name));
|
|
94
|
+
return EXIT_MISUSED;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAO/C,eAAO,MAAM,KAAK,QAsB+D,CAAC;AAyBlF,eAAO,MAAM,cAAc,SACnB,SAAS,MAAM,EAAE,YACb,QAAQ,OACb,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KACtC,OAAO,CAAC,IAAI,CAyId,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { LENSES } from "@coldtea/pr-lens-schema";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { parseOptions, readBoolean, readInt, readList, readString } from "../args.js";
|
|
4
|
+
import { discoverConfig, loadConfig } from "../config-file.js";
|
|
5
|
+
import { PrLensCliError, usageError } from "../errors.js";
|
|
6
|
+
import { extractGraph } from "../extract.js";
|
|
7
|
+
import { collectDiff, mergeBase, parseRepoSlug, remoteSlug, repositoryRoot, resolveCommit } from "../git.js";
|
|
8
|
+
import { readTextFile, writeJsonFile } from "../io.js";
|
|
9
|
+
import { buildExtractionPrompt, SYSTEM_PROMPT } from "../prompt.js";
|
|
10
|
+
import { completeJson, isProviderId, PROVIDER_IDS, resolveProvider } from "../providers/index.js";
|
|
11
|
+
import { CLI_VERSION, GENERATOR_NAME } from "../version.js";
|
|
12
|
+
const DEFAULT_OUT = "pr-lens/graph.json";
|
|
13
|
+
const DEFAULT_MAX_OUTPUT_TOKENS = 32_768;
|
|
14
|
+
const DEFAULT_MAX_DIFF_BYTES = 400_000;
|
|
15
|
+
export const USAGE = `pr-lens analyze --base <ref> [options]
|
|
16
|
+
|
|
17
|
+
Reads the diff between two commits and asks your own model to describe it as a
|
|
18
|
+
graph document. The key never leaves your machine: it is read from the
|
|
19
|
+
environment, and the diff goes straight to the provider you name.
|
|
20
|
+
|
|
21
|
+
--base <ref> what the change is measured against (required)
|
|
22
|
+
--head <ref> the tip of the change (default HEAD)
|
|
23
|
+
--repo <dir> repository to read (default .)
|
|
24
|
+
--provider <id> ${PROVIDER_IDS.join(" | ")} (default gemini)
|
|
25
|
+
--model <name> model to ask (required for openai-compatible)
|
|
26
|
+
--base-url <url> provider endpoint, for a compatible or local server
|
|
27
|
+
--api-key-env <name> environment variable holding the key
|
|
28
|
+
--lens <lens> ${LENSES.join(", ")} (repeatable, default both)
|
|
29
|
+
--config <file> read the lenses from this config (default the repository's)
|
|
30
|
+
--no-config ignore the repository's config
|
|
31
|
+
--pr <number> pull request number, recorded in provenance
|
|
32
|
+
--repo-slug <owner/name> override the slug read from the git remote
|
|
33
|
+
--remote <name> remote to read the slug from (default origin)
|
|
34
|
+
--max-diff-bytes <n> truncate the diff sent to the model (default ${DEFAULT_MAX_DIFF_BYTES})
|
|
35
|
+
--max-output-tokens <n> room for the answer (default ${DEFAULT_MAX_OUTPUT_TOKENS})
|
|
36
|
+
--dry-run report what would be sent, and send nothing
|
|
37
|
+
-o, --out <file> where to write the document (default ${DEFAULT_OUT})`;
|
|
38
|
+
const readLenses = (values) => {
|
|
39
|
+
const requested = readList(values.lens, "lens");
|
|
40
|
+
if (requested === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
const unknown = requested.filter((lens) => !LENSES.some((known) => known === lens));
|
|
43
|
+
if (unknown.length > 0)
|
|
44
|
+
throw usageError(`unknown lens ${unknown.join(", ")}`, `known lenses: ${LENSES.join(", ")}`);
|
|
45
|
+
return LENSES.filter((lens) => requested.includes(lens));
|
|
46
|
+
};
|
|
47
|
+
const readProviderId = (values) => {
|
|
48
|
+
const id = readString(values.provider, "provider") ?? "gemini";
|
|
49
|
+
if (!isProviderId(id))
|
|
50
|
+
throw usageError(`unknown provider ${JSON.stringify(id)}`, `known providers: ${PROVIDER_IDS.join(", ")}`);
|
|
51
|
+
return id;
|
|
52
|
+
};
|
|
53
|
+
const graphJsonSchema = () => readTextFile(createRequire(import.meta.url).resolve("@coldtea/pr-lens-schema/json-schema/graph-doc.schema.json"));
|
|
54
|
+
export const analyzeCommand = async (args, terminal, env) => {
|
|
55
|
+
const { values, positionals } = parseOptions(args, {
|
|
56
|
+
base: { type: "string" },
|
|
57
|
+
head: { type: "string" },
|
|
58
|
+
repo: { type: "string" },
|
|
59
|
+
provider: { type: "string" },
|
|
60
|
+
model: { type: "string" },
|
|
61
|
+
"base-url": { type: "string" },
|
|
62
|
+
"api-key-env": { type: "string" },
|
|
63
|
+
lens: { type: "string", multiple: true },
|
|
64
|
+
config: { type: "string" },
|
|
65
|
+
"no-config": { type: "boolean" },
|
|
66
|
+
pr: { type: "string" },
|
|
67
|
+
"repo-slug": { type: "string" },
|
|
68
|
+
remote: { type: "string" },
|
|
69
|
+
"max-diff-bytes": { type: "string" },
|
|
70
|
+
"max-output-tokens": { type: "string" },
|
|
71
|
+
"dry-run": { type: "boolean" },
|
|
72
|
+
out: { type: "string", short: "o" },
|
|
73
|
+
});
|
|
74
|
+
if (positionals.length > 0)
|
|
75
|
+
throw usageError(`analyze takes no positional arguments, got ${positionals.join(" ")}`);
|
|
76
|
+
const base = readString(values.base, "base");
|
|
77
|
+
if (base === undefined)
|
|
78
|
+
throw usageError("--base is required", "it names the commit the change is measured against, e.g. --base origin/main");
|
|
79
|
+
const repo = readString(values.repo, "repo") ?? process.cwd();
|
|
80
|
+
const head = readString(values.head, "head") ?? "HEAD";
|
|
81
|
+
const maxDiffBytes = readInt(values["max-diff-bytes"], "max-diff-bytes", DEFAULT_MAX_DIFF_BYTES);
|
|
82
|
+
const slugOption = readString(values["repo-slug"], "repo-slug");
|
|
83
|
+
const slug = slugOption === undefined
|
|
84
|
+
? await remoteSlug(repo, readString(values.remote, "remote") ?? "origin")
|
|
85
|
+
: parseRepoSlug(slugOption);
|
|
86
|
+
if (slug === undefined)
|
|
87
|
+
throw new PrLensCliError("REPOSITORY_UNKNOWN", "cannot tell which repository this is", "pass --repo-slug owner/name, or add a git remote the CLI can read");
|
|
88
|
+
const configPath = readString(values.config, "config");
|
|
89
|
+
const configured = readBoolean(values["no-config"])
|
|
90
|
+
? undefined
|
|
91
|
+
: configPath === undefined
|
|
92
|
+
? await discoverConfig(await repositoryRoot(repo))
|
|
93
|
+
: await loadConfig(configPath);
|
|
94
|
+
const requestedLenses = readLenses(values);
|
|
95
|
+
const lenses = requestedLenses ?? configured?.config.lenses ?? [...LENSES];
|
|
96
|
+
const headCommit = await resolveCommit(repo, head);
|
|
97
|
+
const baseCommit = await resolveCommit(repo, base);
|
|
98
|
+
const comparedAgainst = await mergeBase(repo, baseCommit.sha, headCommit.sha);
|
|
99
|
+
const diff = await collectDiff(repo, comparedAgainst, headCommit.sha, maxDiffBytes);
|
|
100
|
+
if (diff.files.length === 0)
|
|
101
|
+
throw new PrLensCliError("EMPTY_DIFF", `${base} and ${head} have the same content`, "there is nothing to draw");
|
|
102
|
+
const promptContext = {
|
|
103
|
+
repo: { owner: slug.owner, name: slug.name },
|
|
104
|
+
base: { sha: comparedAgainst, ref: baseCommit.ref },
|
|
105
|
+
head: { sha: headCommit.sha, ref: headCommit.ref },
|
|
106
|
+
diff,
|
|
107
|
+
lenses,
|
|
108
|
+
};
|
|
109
|
+
const user = buildExtractionPrompt(promptContext, await graphJsonSchema());
|
|
110
|
+
const provider = readBoolean(values["dry-run"])
|
|
111
|
+
? undefined
|
|
112
|
+
: resolveProvider({
|
|
113
|
+
id: readProviderId(values),
|
|
114
|
+
model: readString(values.model, "model"),
|
|
115
|
+
baseUrl: readString(values["base-url"], "base-url"),
|
|
116
|
+
apiKeyEnv: readString(values["api-key-env"], "api-key-env"),
|
|
117
|
+
}, env);
|
|
118
|
+
terminal.err(`${diff.files.length} files, +${diff.additions} -${diff.deletions}, ${Buffer.byteLength(diff.patch, "utf8")} bytes of diff${diff.truncatedAt === undefined ? "" : " (truncated)"}`);
|
|
119
|
+
terminal.err(`prompt: ${Buffer.byteLength(user, "utf8")} bytes`);
|
|
120
|
+
if (provider === undefined) {
|
|
121
|
+
terminal.out(`✓ dry run — nothing was sent, and nothing was written`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const pr = values.pr === undefined ? undefined : readInt(values.pr, "pr", 0);
|
|
125
|
+
const pullRequest = pr === undefined
|
|
126
|
+
? undefined
|
|
127
|
+
: { number: pr, url: `https://${slug.host}/${slug.owner}/${slug.name}/pull/${pr}` };
|
|
128
|
+
const provenance = {
|
|
129
|
+
repo: slug,
|
|
130
|
+
base: { sha: comparedAgainst, ref: baseCommit.ref },
|
|
131
|
+
head: { sha: headCommit.sha, ref: headCommit.ref },
|
|
132
|
+
...(pullRequest === undefined ? {} : { pullRequest }),
|
|
133
|
+
generator: { name: GENERATOR_NAME, version: CLI_VERSION, model: provider.model },
|
|
134
|
+
};
|
|
135
|
+
terminal.err(`asking ${provider.id} (${provider.model})…`);
|
|
136
|
+
const { document, attempts } = await extractGraph({
|
|
137
|
+
system: SYSTEM_PROMPT,
|
|
138
|
+
user,
|
|
139
|
+
maxOutputTokens: readInt(values["max-output-tokens"], "max-output-tokens", DEFAULT_MAX_OUTPUT_TOKENS),
|
|
140
|
+
known: {
|
|
141
|
+
provenance,
|
|
142
|
+
lenses,
|
|
143
|
+
stats: {
|
|
144
|
+
filesChanged: diff.files.length,
|
|
145
|
+
additions: diff.additions,
|
|
146
|
+
deletions: diff.deletions,
|
|
147
|
+
},
|
|
148
|
+
generatedAt: new Date().toISOString(),
|
|
149
|
+
},
|
|
150
|
+
onAttempt: (attempt) => {
|
|
151
|
+
if (attempt > 1)
|
|
152
|
+
terminal.err(`the document did not validate — asking for a correction`);
|
|
153
|
+
},
|
|
154
|
+
}, (request) => completeJson(provider, request));
|
|
155
|
+
const written = await writeJsonFile(readString(values.out, "out") ?? DEFAULT_OUT, document);
|
|
156
|
+
terminal.out(`✓ ${written} — ${document.nodes.length} nodes, ${document.edges.length} edges, ${document.flows.length} flows${attempts > 1 ? ` (${attempts} attempts)` : ""}`);
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiC,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,UAAU,EAAqB,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC7G,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAElG,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE5D,MAAM,WAAW,GAAG,oBAAoB,CAAC;AACzC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AACzC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAEvC,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;8BASS,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;;;;8BAIxB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;2EAM4B,sBAAsB;2DACtC,yBAAyB;;mEAEjB,WAAW,GAAG,CAAC;AAElF,MAAM,UAAU,GAAG,CAAC,MAA+B,EAAsB,EAAE;IACzE,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChD,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC;IACpF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QACpB,MAAM,UAAU,CAAC,gBAAgB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,iBAAiB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE/F,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3D,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,MAA+B,EAAE,EAAE;IACzD,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,QAAQ,CAAC;IAC/D,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACnB,MAAM,UAAU,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,oBAAoB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5G,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,GAAoB,EAAE,CAC5C,YAAY,CACV,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,2DAA2D,CAAC,CACpG,CAAC;AAEJ,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EACjC,IAAuB,EACvB,QAAkB,EAClB,GAAuC,EACxB,EAAE;IACjB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE;QACjD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC9B,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACjC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;QACxC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC1B,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAChC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACtB,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC1B,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACpC,mBAAmB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACvC,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC9B,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;KACpC,CAAC,CAAC;IAEH,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,UAAU,CAAC,8CAA8C,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEpH,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,UAAU,CAAC,oBAAoB,EAAE,6EAA6E,CAAC,CAAC;IAE9I,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC9D,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC;IACvD,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,EAAE,sBAAsB,CAAC,CAAC;IAEjG,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,UAAU,KAAK,SAAS;QACnC,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,QAAQ,CAAC;QACzE,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAE9B,IAAI,IAAI,KAAK,SAAS;QACpB,MAAM,IAAI,cAAc,CACtB,oBAAoB,EACpB,sCAAsC,EACtC,mEAAmE,CACpE,CAAC;IAEJ,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvD,MAAM,UAAU,GAA6B,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3E,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,UAAU,KAAK,SAAS;YACxB,CAAC,CAAC,MAAM,cAAc,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;YAClD,CAAC,CAAC,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAEnC,MAAM,eAAe,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,eAAe,IAAI,UAAU,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;IAE3E,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,MAAM,eAAe,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAEpF,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QACzB,MAAM,IAAI,cAAc,CACtB,YAAY,EACZ,GAAG,IAAI,QAAQ,IAAI,wBAAwB,EAC3C,0BAA0B,CAC3B,CAAC;IAEJ,MAAM,aAAa,GAAG;QACpB,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;QAC5C,IAAI,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE;QACnD,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE;QAClD,IAAI;QACJ,MAAM;KACP,CAAC;IAEF,MAAM,IAAI,GAAG,qBAAqB,CAAC,aAAa,EAAE,MAAM,eAAe,EAAE,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC7C,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,eAAe,CACb;YACE,EAAE,EAAE,cAAc,CAAC,MAAM,CAAC;YAC1B,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;YACxC,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;YACnD,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;SAC5D,EACD,GAAG,CACJ,CAAC;IAEN,QAAQ,CAAC,GAAG,CACV,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,YAAY,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,iBAAiB,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,CACnL,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEjE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,QAAQ,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,WAAW,GACf,EAAE,KAAK,SAAS;QACd,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,WAAW,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,SAAS,EAAE,EAAE,EAAE,CAAC;IAExF,MAAM,UAAU,GAAgC;QAC9C,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE;QACnD,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE;QAClD,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;QACrD,SAAS,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE;KACjF,CAAC;IAEF,QAAQ,CAAC,GAAG,CAAC,UAAU,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;IAE3D,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAC/C;QACE,MAAM,EAAE,aAAa;QACrB,IAAI;QACJ,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,yBAAyB,CAAC;QACrG,KAAK,EAAE;YACL,UAAU;YACV,MAAM;YACN,KAAK,EAAE;gBACL,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;gBAC/B,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B;YACD,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC;QACD,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;YACrB,IAAI,OAAO,GAAG,CAAC;gBAAE,QAAQ,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QAC3F,CAAC;KACF,EACD,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAC7C,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC5F,QAAQ,CAAC,GAAG,CACV,KAAK,OAAO,MAAM,QAAQ,CAAC,KAAK,CAAC,MAAM,WAAW,QAAQ,CAAC,KAAK,CAAC,MAAM,WAAW,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAChK,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Terminal } from "../terminal.js";
|
|
2
|
+
export declare const USAGE = "pr-lens comment --graph <graph.json> --manifest <manifest.json> [options]\n\nComposes the pull request comment: the diagrams as light/dark <picture> pairs,\nthe headline numbers, and the drill-down tree. It posts nothing \u2014 the markdown\ngoes to stdout, or to a file, for whatever does the posting.\n\n --graph <file> the document that was rendered \u2014 the one the render\n wrote beside the manifest, not the one it read\n --manifest <file> what the render produced (required)\n --asset-base-url <url> where the rendered SVGs are published, when the\n manifest records local paths\n --config <file> read 'branding' from a repository config\n --no-branding leave off the PR Lens footer\n --print-marker print the hidden marker that identifies the\n comment, and nothing else\n -o, --out <file> write the markdown here instead of stdout";
|
|
3
|
+
export declare const commentCommand: (args: readonly string[], terminal: Terminal) => Promise<void>;
|
|
4
|
+
//# sourceMappingURL=comment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,eAAO,MAAM,KAAK,0/BAesD,CAAC;AAEzE,eAAO,MAAM,cAAc,SAAgB,SAAS,MAAM,EAAE,YAAY,QAAQ,KAAG,OAAO,CAAC,IAAI,CAkD9F,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { graphContentHash } from "@coldtea/pr-lens-renderer";
|
|
2
|
+
import { parseOptions, readBoolean, readString } from "../args.js";
|
|
3
|
+
import { composeComment, COMMENT_MARKER } from "../comment.js";
|
|
4
|
+
import { loadConfig } from "../config-file.js";
|
|
5
|
+
import { readGraphDoc, readRenderManifest } from "../document.js";
|
|
6
|
+
import { usageError } from "../errors.js";
|
|
7
|
+
import { writeTextFile } from "../io.js";
|
|
8
|
+
export const USAGE = `pr-lens comment --graph <graph.json> --manifest <manifest.json> [options]
|
|
9
|
+
|
|
10
|
+
Composes the pull request comment: the diagrams as light/dark <picture> pairs,
|
|
11
|
+
the headline numbers, and the drill-down tree. It posts nothing — the markdown
|
|
12
|
+
goes to stdout, or to a file, for whatever does the posting.
|
|
13
|
+
|
|
14
|
+
--graph <file> the document that was rendered — the one the render
|
|
15
|
+
wrote beside the manifest, not the one it read
|
|
16
|
+
--manifest <file> what the render produced (required)
|
|
17
|
+
--asset-base-url <url> where the rendered SVGs are published, when the
|
|
18
|
+
manifest records local paths
|
|
19
|
+
--config <file> read 'branding' from a repository config
|
|
20
|
+
--no-branding leave off the PR Lens footer
|
|
21
|
+
--print-marker print the hidden marker that identifies the
|
|
22
|
+
comment, and nothing else
|
|
23
|
+
-o, --out <file> write the markdown here instead of stdout`;
|
|
24
|
+
export const commentCommand = async (args, terminal) => {
|
|
25
|
+
const { values, positionals } = parseOptions(args, {
|
|
26
|
+
graph: { type: "string" },
|
|
27
|
+
manifest: { type: "string" },
|
|
28
|
+
"asset-base-url": { type: "string" },
|
|
29
|
+
config: { type: "string" },
|
|
30
|
+
"no-branding": { type: "boolean" },
|
|
31
|
+
"print-marker": { type: "boolean" },
|
|
32
|
+
out: { type: "string", short: "o" },
|
|
33
|
+
});
|
|
34
|
+
if (positionals.length > 0)
|
|
35
|
+
throw usageError(`comment takes no positional arguments, got ${positionals.join(" ")}`);
|
|
36
|
+
if (readBoolean(values["print-marker"])) {
|
|
37
|
+
terminal.out(COMMENT_MARKER);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const graphPath = readString(values.graph, "graph");
|
|
41
|
+
const manifestPath = readString(values.manifest, "manifest");
|
|
42
|
+
if (graphPath === undefined || manifestPath === undefined)
|
|
43
|
+
throw usageError("--graph and --manifest are both required");
|
|
44
|
+
const configPath = readString(values.config, "config");
|
|
45
|
+
const configured = configPath === undefined ? undefined : await loadConfig(configPath);
|
|
46
|
+
const graph = await readGraphDoc(graphPath);
|
|
47
|
+
const manifest = await readRenderManifest(manifestPath);
|
|
48
|
+
if (graphContentHash(graph) !== manifest.graph.contentHash)
|
|
49
|
+
throw usageError(`${graphPath} is not the document ${manifestPath} describes`, "corrections change what the diagrams show, so a comment built from a different document would announce sections that were never drawn. Pass the drawn.graph.json the render wrote beside the manifest");
|
|
50
|
+
const body = composeComment({
|
|
51
|
+
graph,
|
|
52
|
+
manifest,
|
|
53
|
+
assetBaseUrl: readString(values["asset-base-url"], "asset-base-url"),
|
|
54
|
+
branding: readBoolean(values["no-branding"]) ? false : (configured?.config.branding ?? true),
|
|
55
|
+
});
|
|
56
|
+
const out = readString(values.out, "out");
|
|
57
|
+
if (out === undefined) {
|
|
58
|
+
terminal.out(body.trimEnd());
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
terminal.err(`✓ ${await writeTextFile(out, body)}`);
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=comment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Terminal } from "../terminal.js";
|
|
2
|
+
export declare const USAGE = "pr-lens export <graph.json> [options]\n\nTurns a pull-request document into the stored map of the system once that pull\nrequest has merged: elements the change deletes are dropped, the rest stops\nbeing annotated, and the result is stamped with the single commit it reflects.\n\nThe map is a snapshot, not a source of truth \u2014 nothing reads it back into the\npipeline. Committing it gives a repository something to read, to diff, and to\nhand an agent.\n\n -o, --out <file> where to write it (default .github/pr-lens.map.json)\n --id <id> map id, so a patch can name it (default <owner>/<name>)\n --sha <sha> the commit it reflects, in full (default the document's head)";
|
|
3
|
+
export declare const exportCommand: (args: readonly string[], terminal: Terminal) => Promise<void>;
|
|
4
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI/C,eAAO,MAAM,KAAK,6rBAYiE,CAAC;AAEpF,eAAO,MAAM,aAAa,SAAgB,SAAS,MAAM,EAAE,YAAY,QAAQ,KAAG,OAAO,CAAC,IAAI,CAqC7F,CAAC"}
|