lastlight 0.7.5 → 0.7.7
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/config/default.yaml +1 -0
- package/dist/admin/auth.d.ts +25 -0
- package/dist/admin/auth.js +55 -10
- package/dist/admin/auth.js.map +1 -1
- package/dist/admin/routes.js +18 -1
- package/dist/admin/routes.js.map +1 -1
- package/dist/cli/cli-config.d.ts +9 -1
- package/dist/cli/cli-config.js +22 -0
- package/dist/cli/cli-config.js.map +1 -1
- package/dist/cli/cli.js +60 -4
- package/dist/cli/cli.js.map +1 -1
- package/dist/config/config.js +1 -0
- package/dist/config/config.js.map +1 -1
- package/dist/engine/dispatcher.js +19 -1
- package/dist/engine/dispatcher.js.map +1 -1
- package/dist/engine/executors/orchestrator.js +10 -1
- package/dist/engine/executors/orchestrator.js.map +1 -1
- package/dist/engine/github/github-app-client.d.ts +16 -0
- package/dist/engine/github/github-app-client.js +17 -0
- package/dist/engine/github/github-app-client.js.map +1 -1
- package/dist/engine/github/github.d.ts +33 -0
- package/dist/engine/github/github.js +51 -1
- package/dist/engine/github/github.js.map +1 -1
- package/dist/engine/github/review-poster.d.ts +98 -0
- package/dist/engine/github/review-poster.js +177 -0
- package/dist/engine/github/review-poster.js.map +1 -0
- package/dist/engine/router.js +8 -4
- package/dist/engine/router.js.map +1 -1
- package/dist/engine/screen/classifier.js +8 -3
- package/dist/engine/screen/classifier.js.map +1 -1
- package/dist/workflows/phase-executor.d.ts +24 -0
- package/dist/workflows/phase-executor.js +186 -0
- package/dist/workflows/phase-executor.js.map +1 -1
- package/dist/workflows/schema.d.ts +2 -0
- package/dist/workflows/schema.js +9 -1
- package/dist/workflows/schema.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lastlight/.claude-plugin/plugin.json +12 -3
- package/plugins/lastlight/skills/lastlight-evals/SKILL.md +9 -1
- package/skills/pr-review/SKILL.md +83 -33
- package/skills/pr-review/references/findings-schema.md +89 -0
- package/workflows/pr-review.yaml +21 -0
|
@@ -1,36 +1,42 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pr-review
|
|
3
3
|
description: Review a GitHub pull request and post one formal review — advance the existing discussion and give precision-first, high-signal feedback. A pure code review — no building. Use when asked to review a PR or on a cron PR scan.
|
|
4
|
-
version:
|
|
4
|
+
version: 7.0.0
|
|
5
5
|
tags: [github, review, code-quality]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# PR Review
|
|
9
9
|
|
|
10
|
-
Review an open PR
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
Review an open PR — high-signal findings only. This is a **pure code review**:
|
|
11
|
+
read the change and reason about it. Do **not** install dependencies, build, or
|
|
12
|
+
run tests — that is CI's job, and it validates whether the change actually works
|
|
13
|
+
far more reliably than you re-running it here. Your job is judgement on the diff,
|
|
14
|
+
not a build gate. A noisy review gets muted, so precision matters more than
|
|
15
|
+
volume.
|
|
16
|
+
|
|
17
|
+
You do **not** post the review yourself. You write your findings to a JSON file
|
|
18
|
+
(`.lastlight/pr-review/findings.json`) and a deterministic follow-up step posts
|
|
19
|
+
one formal review, anchoring each finding to its diff line as an inline comment
|
|
20
|
+
(§4).
|
|
16
21
|
|
|
17
22
|
This skill is the PR-specific procedure. It uses the **code-review** skill for
|
|
18
23
|
the precision bar and what-to-check rubric.
|
|
19
24
|
|
|
20
25
|
## Workspace
|
|
21
26
|
|
|
22
|
-
The harness pre-clones the PR's head ref
|
|
23
|
-
your cwd
|
|
24
|
-
|
|
27
|
+
The harness pre-clones the PR's head ref and drops you **inside the checkout** —
|
|
28
|
+
your cwd **is** the repo (`ls -la` shows `.git/` directly; `AGENTS.md` is the
|
|
29
|
+
sibling one level up at `../`). Use `git`/`read`/`grep` from here. To refresh:
|
|
25
30
|
`git fetch origin <branch> --depth 50 && git reset --hard FETCH_HEAD`. If the
|
|
26
|
-
|
|
31
|
+
checkout is somehow missing, `git clone https://github.com/{{owner}}/{{repo}}.git .`.
|
|
27
32
|
|
|
28
33
|
**Read code from this local checkout, never the API.** Use `git`/`read`/`grep`
|
|
29
34
|
on disk for the diff and file contents. Do **not** call
|
|
30
35
|
`github_get_pull_request_diff`, `github_list_pull_request_files`, or
|
|
31
36
|
`github_get_file_contents` — the API patch is a large redundant payload that
|
|
32
37
|
re-bloats context every turn. The `github_*` tools are for *API* operations only
|
|
33
|
-
(metadata
|
|
38
|
+
(reading metadata + prior comments in §1–2). You never post the review via a
|
|
39
|
+
tool — you write the findings file and the follow-up step posts it.
|
|
34
40
|
|
|
35
41
|
## Procedure
|
|
36
42
|
|
|
@@ -66,33 +72,77 @@ git diff --stat origin/<baseRef>...HEAD # churn
|
|
|
66
72
|
git diff origin/<baseRef>...HEAD # the patch
|
|
67
73
|
```
|
|
68
74
|
|
|
69
|
-
### 4. Assess and
|
|
75
|
+
### 4. Assess and write your findings
|
|
70
76
|
|
|
71
77
|
Apply the **code-review** skill's rubric — read each changed file in context;
|
|
72
78
|
check correctness / edge-cases / security / regression-risk / test-coverage.
|
|
73
79
|
Reason about the code statically; **don't build or run it** — trust CI to catch
|
|
74
80
|
what only running reveals, and spend your effort on what a human reviewer sees.
|
|
75
|
-
Follow that skill's **precision-first** rule:
|
|
76
|
-
findings, each
|
|
77
|
-
breaks, for which input or caller)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
Follow that skill's **precision-first** rule: keep **only Critical and Important**
|
|
82
|
+
findings, each anchored to a `path:line` with a one-line concrete impact (what
|
|
83
|
+
breaks, for which input or caller). Drop Suggestions and Nits.
|
|
84
|
+
|
|
85
|
+
Before writing anything, run the **confidence gate**: re-read each finding
|
|
86
|
+
against the actual code and try to refute it; drop any you can't defend against
|
|
87
|
+
what the code really does. A clean PR should be approved with few or no
|
|
88
|
+
findings — that is a good review, not a lazy one.
|
|
89
|
+
|
|
90
|
+
**Do not call `github_create_pull_request_review` (or any review-submitting
|
|
91
|
+
tool).** Write your findings to `.lastlight/pr-review/findings.json` instead. A
|
|
92
|
+
deterministic follow-up step reads that file and posts one formal review with
|
|
93
|
+
your findings as inline comments anchored to the diff. The full contract with
|
|
94
|
+
worked examples is in [references/findings-schema.md](references/findings-schema.md);
|
|
95
|
+
the shape is:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"skip": false,
|
|
100
|
+
"summary": "One or two sentences on what the PR does + overall assessment.",
|
|
101
|
+
"event": "COMMENT",
|
|
102
|
+
"findings": [
|
|
103
|
+
{
|
|
104
|
+
"path": "src/foo.ts",
|
|
105
|
+
"line": 42,
|
|
106
|
+
"side": "RIGHT",
|
|
107
|
+
"severity": "Critical",
|
|
108
|
+
"title": "Short label for the finding",
|
|
109
|
+
"body": "Concrete impact — what breaks, for which input or caller.",
|
|
110
|
+
"suggestion": "exact replacement text for the anchored line(s)"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
```
|
|
91
115
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
Write **only these content fields** — `skip?` / `summary` / `event` /
|
|
117
|
+
`findings[]`. The follow-up step already knows the PR number, base ref, head
|
|
118
|
+
SHA and diff from the harness's own context and the checkout, so you do **not**
|
|
119
|
+
record any of that metadata (that reliance was a footgun — omit it).
|
|
120
|
+
|
|
121
|
+
Rules:
|
|
122
|
+
- **Anchor precisely.** `path` must match the diff path exactly; `line`/`side`
|
|
123
|
+
must point at a line that appears in the diff (added/context → `side: RIGHT`;
|
|
124
|
+
removed/context → `side: LEFT`). A finding whose line isn't in the diff is
|
|
125
|
+
demoted to the summary body, so get the anchor right. Use optional `start_line`
|
|
126
|
+
(same side) for a multi-line range.
|
|
127
|
+
- `severity` is `Critical` or `Important` only.
|
|
128
|
+
- `suggestion` is optional — include it only when a concrete one-to-few-line fix
|
|
129
|
+
is obvious. It must be the exact replacement text for the anchored line(s),
|
|
130
|
+
nothing else; GitHub renders it as an applyable suggestion.
|
|
131
|
+
- `event` is `APPROVE` / `REQUEST_CHANGES` / `COMMENT`, matching what survived
|
|
132
|
+
the gate. A clean PR is an `APPROVE` with an empty `findings` array and a short
|
|
133
|
+
`summary`.
|
|
134
|
+
- Create the dir and keep the file out of git first:
|
|
135
|
+
`mkdir -p .lastlight/pr-review && echo '.lastlight/' >> .git/info/exclude`.
|
|
136
|
+
|
|
137
|
+
**Stop / skip:** if a stop condition in §1 holds (bot-authored, merged, already
|
|
138
|
+
reviewed at the current head SHA), write `{"skip": true, "summary": "<reason>"}`
|
|
139
|
+
and stop — the follow-up step then posts nothing.
|
|
95
140
|
|
|
96
141
|
## Verification
|
|
97
142
|
|
|
98
|
-
Confirm
|
|
143
|
+
Confirm `.lastlight/pr-review/findings.json` is valid JSON and every finding
|
|
144
|
+
carries `path` + `line`. The first-class `post-review` action then posts the
|
|
145
|
+
review — anchoring each finding to its diff line, demoting any off-diff finding
|
|
146
|
+
to the body, and logging how many landed inline vs in the body. If the file is
|
|
147
|
+
missing after a real review (not a `skip`), that step **fails the run** loudly
|
|
148
|
+
rather than posting nothing.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# PR review findings schema
|
|
2
|
+
|
|
3
|
+
The `pr-review` skill writes its findings to `.lastlight/pr-review/findings.json`
|
|
4
|
+
(relative to the repo checkout — your cwd). The first-class `post-review` action
|
|
5
|
+
reads this file and posts **one** formal GitHub review:
|
|
6
|
+
|
|
7
|
+
- Each finding whose `line`/`side` anchors to a line that appears in the PR diff
|
|
8
|
+
becomes an **inline comment** on that exact line.
|
|
9
|
+
- Any finding whose anchor isn't in the diff is **demoted** into the review body
|
|
10
|
+
under an "Additional findings" heading (GitHub rejects comments off the diff).
|
|
11
|
+
- If the diff can't be computed (git failure), **all** findings go into the
|
|
12
|
+
body — the review still posts, so nothing is lost.
|
|
13
|
+
|
|
14
|
+
You write only the review **content** — `skip?` / `summary` / `event` /
|
|
15
|
+
`findings[]`. The PR number, base ref, head SHA and diff come from the harness's
|
|
16
|
+
own run context and the checkout, so you do **not** record any of that metadata.
|
|
17
|
+
You never call `github_create_pull_request_review` yourself; writing this file is
|
|
18
|
+
how you submit.
|
|
19
|
+
|
|
20
|
+
## Top-level object
|
|
21
|
+
|
|
22
|
+
| Field | Type | Required | Meaning |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `skip` | boolean | no | `true` → you decided not to review (bot-authored / merged / already reviewed at head). The action posts nothing. |
|
|
25
|
+
| `summary` | string | yes | One or two sentences on what the PR does + your overall assessment. Becomes the review body. |
|
|
26
|
+
| `event` | string | yes | `APPROVE` \| `REQUEST_CHANGES` \| `COMMENT`. A clean PR is `APPROVE` with an empty `findings` array. |
|
|
27
|
+
| `findings` | array | yes | The surviving Critical/Important findings (may be empty). |
|
|
28
|
+
|
|
29
|
+
## Finding object
|
|
30
|
+
|
|
31
|
+
| Field | Type | Required | Meaning |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `path` | string | yes | Repo-relative file path, matching the diff path exactly. |
|
|
34
|
+
| `line` | number | yes | Line number on `side` that the comment anchors to. Must appear in the diff. |
|
|
35
|
+
| `side` | string | no | `RIGHT` (added/context line — default) or `LEFT` (removed/context line). |
|
|
36
|
+
| `start_line` | number | no | Start of a multi-line range (same `side` as `line`). |
|
|
37
|
+
| `severity` | string | yes | `Critical` or `Important` only. |
|
|
38
|
+
| `title` | string | yes | Short label for the finding. |
|
|
39
|
+
| `body` | string | yes | Concrete impact — what breaks, for which input or caller. |
|
|
40
|
+
| `suggestion` | string | no | Exact replacement text for the anchored line(s). Rendered as an applyable ```suggestion block. Include only when a concrete one-to-few-line fix is obvious. |
|
|
41
|
+
|
|
42
|
+
## Example — findings with an inline suggestion
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"skip": false,
|
|
47
|
+
"summary": "Adds a `--config` flag to the CLI and threads it into the connect path. Solid overall; one crash on the default path and one missing-await.",
|
|
48
|
+
"event": "REQUEST_CHANGES",
|
|
49
|
+
"findings": [
|
|
50
|
+
{
|
|
51
|
+
"path": "src/cli.ts",
|
|
52
|
+
"line": 42,
|
|
53
|
+
"side": "RIGHT",
|
|
54
|
+
"severity": "Critical",
|
|
55
|
+
"title": "Null deref when --config is omitted",
|
|
56
|
+
"body": "`cfg.host` is undefined when no config file is passed, so every default-path invocation throws before connecting.",
|
|
57
|
+
"suggestion": "const host = cfg.host ?? DEFAULT_HOST;"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"path": "src/connect.ts",
|
|
61
|
+
"line": 88,
|
|
62
|
+
"side": "RIGHT",
|
|
63
|
+
"severity": "Important",
|
|
64
|
+
"title": "Missing await on disconnect()",
|
|
65
|
+
"body": "`disconnect()` returns a promise that's never awaited, so the socket can leak if the caller exits immediately after."
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Example — clean PR (approve, no findings)
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"skip": false,
|
|
76
|
+
"summary": "Small, well-tested refactor of the retry helper. No correctness or regression concerns.",
|
|
77
|
+
"event": "APPROVE",
|
|
78
|
+
"findings": []
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Example — skip (already reviewed this SHA)
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"skip": true,
|
|
87
|
+
"summary": "A last-light[bot] review already exists on the current head SHA; nothing new to add."
|
|
88
|
+
}
|
|
89
|
+
```
|
package/workflows/pr-review.yaml
CHANGED
|
@@ -16,6 +16,27 @@ phases:
|
|
|
16
16
|
# pr-review: the PR procedure (primary). code-review: the finding-tier +
|
|
17
17
|
# what-to-check rubric. No `building` — pr-review is a pure code review; CI
|
|
18
18
|
# validates that the change builds/runs.
|
|
19
|
+
#
|
|
20
|
+
# The agent does NOT submit the review itself — it writes structured
|
|
21
|
+
# findings (content only: skip? / summary / event / findings[]) to
|
|
22
|
+
# .lastlight/pr-review/findings.json. The first-class `post-review` action
|
|
23
|
+
# below reads that file and posts one formal review.
|
|
19
24
|
skills: [pr-review, code-review]
|
|
20
25
|
model: "{{models.review}}"
|
|
21
26
|
variant: "{{variants.review}}"
|
|
27
|
+
|
|
28
|
+
# First-class, in-process submission (type: post-review → PhaseExecutor.
|
|
29
|
+
# runPostReview). Reads the agent's findings.json for the review *content*
|
|
30
|
+
# (skip? / summary / event / findings[]) and supplies everything else from
|
|
31
|
+
# the harness itself — PR number (run context), base ref (baseBranch), head
|
|
32
|
+
# SHA + diff (the pre-cloned checkout) — so the AI never hand-copies metadata.
|
|
33
|
+
# It anchors each finding to a changed line, demotes off-diff findings to the
|
|
34
|
+
# body (GitHub 422s on off-diff lines), and posts ONE review via GitHubClient
|
|
35
|
+
# (App auth in prod; token + githubApiBaseUrl against the eval mock). A
|
|
36
|
+
# genuine failure — missing findings after a real review, or a GitHub error
|
|
37
|
+
# that survives the body-only retry — FAILS this phase visibly; a legitimate
|
|
38
|
+
# `skip` succeeds without posting. Idempotent on resume (no-op if a bot review
|
|
39
|
+
# already exists on the head SHA).
|
|
40
|
+
- name: post-review
|
|
41
|
+
label: Post inline review
|
|
42
|
+
type: post-review
|