@jphutchins/code-review 0.1.0-alpha.6 โ 0.1.0-alpha.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -14
- package/dist/index.js +6008 -1227
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/schema/VERSIONING.md +65 -3
- package/schema/findings.schema.json +220 -18
- package/schema/prices.example.json +33 -3
- package/schema/prices.schema.json +145 -25
- package/schema/v0.9/findings.schema.json +418 -0
- package/templates/comment.eta +178 -20
- package/templates/inline.eta +24 -9
package/templates/comment.eta
CHANGED
|
@@ -1,52 +1,206 @@
|
|
|
1
1
|
<!-- code-review -->
|
|
2
2
|
<!-- reviewed-sha: <%= it.reviewedSha %> -->
|
|
3
|
-
<% if (it.
|
|
4
|
-
<!--
|
|
5
|
-
<% } else if (it.jsonUrl) { -%>
|
|
6
|
-
<!-- code-review:findings-json <%~ it.jsonUrl %> -->
|
|
3
|
+
<% if (!it.incomplete && it.route) { -%>
|
|
4
|
+
<!-- reviewed-route: <%= it.route %> -->
|
|
7
5
|
<% } -%>
|
|
6
|
+
<% if (!it.incomplete) { -%>
|
|
7
|
+
<!-- review-complete -->
|
|
8
|
+
<% } -%>
|
|
9
|
+
<% if (it.findingsPointer) { -%>
|
|
10
|
+
<%~ it.findingsPointer %>
|
|
11
|
+
<% } -%>
|
|
12
|
+
|
|
13
|
+
## <%= it.verdictBadge(it.findings.verdict) %>
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
<% const meta = [] %><% if (it.postedAt) { meta.push('**Reviewed** `' + it.reviewedSha.slice(0, 7) + '` at ' + it.postedAt) } %><% if (it.route) { meta.push('**route:** ' + it.route) } %><% if (it.effort) { meta.push('**effort:** ' + it.effort) } %><% if (it.hasUsage) { meta.push('**turns:** ' + it.envelope.turns); meta.push('**wall:** ' + it.formatDuration(it.envelope.duration_ms)); meta.push('**models:** ' + it.modelNames); meta.push('**cost:** ' + it.formatCost(it.costReport.totalCostUSD)) } else { meta.push('_usage unavailable_') } %><sub><%~ meta.join(' ยท ') %></sub>
|
|
16
|
+
<% if (!it.incomplete) { -%>
|
|
17
|
+
<% if (it.roundsSummary) { -%>
|
|
18
|
+
<sub><%~ it.roundsSummary %></sub>
|
|
19
|
+
<% } -%>
|
|
20
|
+
<% if (it.convergenceSummary) { -%>
|
|
21
|
+
<sub><%~ it.convergenceSummary %></sub>
|
|
22
|
+
<% } -%>
|
|
23
|
+
<% if (it.changeSummary) { -%>
|
|
24
|
+
<sub>**Changes:** <%~ it.changeSummary %></sub>
|
|
25
|
+
<% } -%>
|
|
26
|
+
<% if (it.clocDiff) { -%>
|
|
27
|
+
<details><summary>๐ cloc</summary>
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
<%~ it.clocDiff %>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
</details>
|
|
10
34
|
|
|
11
|
-
<%
|
|
35
|
+
<% } -%>
|
|
36
|
+
<% if (it.metastasisNote) { -%>
|
|
37
|
+
<%~ it.metastasisNote %>
|
|
38
|
+
<% } -%>
|
|
39
|
+
<% if (it.answeredReRaiseNote) { -%>
|
|
40
|
+
<%~ it.answeredReRaiseNote %>
|
|
41
|
+
<% } -%>
|
|
42
|
+
<% } -%>
|
|
12
43
|
|
|
13
44
|
<%~ it.findings.summary %>
|
|
14
45
|
|
|
46
|
+
<% if (!it.incomplete && it.systemic.length > 0) { -%>
|
|
47
|
+
|
|
48
|
+
## ๐ Systemic problems
|
|
49
|
+
|
|
50
|
+
<% it.systemic.forEach(function(s) { -%>
|
|
51
|
+
### <%= it.severityEmoji(s.severity) %> (<%= s.severity %>) <%= s.title %>
|
|
52
|
+
<sub>confidence <%= it.formatConfidence(s.confidence) %><% if (s.id) { %> ยท id <% if (s.code_url) { %>[`<%~ s.id %>`](<%~ s.code_url %>)<% } else { %>`<%~ s.id %>`<% } %><% } %></sub>
|
|
53
|
+
<% const meta = [] %><% if (s.paths && s.paths.length > 0) { meta.push('Affects: ' + s.paths.map(function(p) { return '`' + p + '`' }).join(', ')) } %><% if (s.finding_ids && s.finding_ids.length > 0) { meta.push('Ties together: ' + s.finding_ids.map(function(c) { return '`' + c + '`' }).join(', ')) } %><% if (meta.length > 0) { %>_<%~ meta.join(' ยท ') %>_<% } %>
|
|
54
|
+
|
|
55
|
+
<%~ s.description %>
|
|
56
|
+
<% if (s.discussionHtml) { -%>
|
|
57
|
+
|
|
58
|
+
<details><summary>๐ฌ Discussion</summary>
|
|
59
|
+
|
|
60
|
+
<%~ s.discussionHtml %>
|
|
61
|
+
</details>
|
|
62
|
+
<% } -%>
|
|
63
|
+
|
|
64
|
+
> <details><summary>Reasoning</summary>
|
|
65
|
+
>
|
|
66
|
+
<% s.reasoning.split("\n").forEach(function(rl) { -%>
|
|
67
|
+
> <%= rl %>
|
|
68
|
+
<% }) -%>
|
|
69
|
+
>
|
|
70
|
+
> </details>
|
|
71
|
+
<% }) -%>
|
|
72
|
+
<% } -%>
|
|
73
|
+
|
|
15
74
|
---
|
|
16
75
|
|
|
17
76
|
<% const c = it.severityCounts %><% const findingsTotal = c.critical + c.major + c.minor + c.nit %>
|
|
77
|
+
<% if (it.unverifiedNoLogs && findingsTotal > 0) { %>
|
|
78
|
+
> [!WARNING]
|
|
79
|
+
> **Unverified โ no failing-job logs were available.** This route reads the failing CI job's log to
|
|
80
|
+
> name the failure; none could be staged for this run, so every finding below was reasoned from the
|
|
81
|
+
> diff or from local reproduction of the checks. Treat them as hypotheses until the failing log is
|
|
82
|
+
> checked.
|
|
83
|
+
|
|
84
|
+
<% } %>
|
|
85
|
+
|
|
18
86
|
<% if (findingsTotal > 0) { %>
|
|
19
87
|
<% const parts = [] %><% if (c.critical) { parts.push(it.severityEmoji('critical') + ' ' + c.critical) } %><% if (c.major) { parts.push(it.severityEmoji('major') + ' ' + c.major) } %><% if (c.minor) { parts.push(it.severityEmoji('minor') + ' ' + c.minor) } %><% if (c.nit) { parts.push(it.severityEmoji('nit') + ' ' + c.nit) } %>
|
|
20
88
|
**Findings:** <%~ parts.join(' ยท ') %>
|
|
21
|
-
<% } else { %>
|
|
22
|
-
_No findings โ clean review._
|
|
89
|
+
<% } else if (!it.incomplete && it.systemic.length === 0 && !it.answeredReRaiseNote) { %>
|
|
90
|
+
<% if (it.unverifiedNoLogs) { %>_No findings โ but no failing-job logs were staged, so this pass could not read the CI failure. "No findings" is not evidence of none._<% } else { %>_No findings โ clean review._<% } %>
|
|
23
91
|
<% } %>
|
|
24
92
|
|
|
25
93
|
<% if (it.inlineDisposition && it.inlineDisposition.kind === 'posted') { %>
|
|
26
|
-
โ <%= it.inlineDisposition.count %> comment<%= it.inlineDisposition.count === 1 ? '' : 's' %> posted inline on `<%= it.inlineDisposition.sha.slice(0, 7)
|
|
94
|
+
โ <%= it.inlineDisposition.count %> comment<%= it.inlineDisposition.count === 1 ? '' : 's' %> posted inline on `<%= it.inlineDisposition.sha.slice(0, 7) %>`<% if (it.reviewUrl) { %> โ [see the review](<%~ it.reviewUrl %>)<% } %>.
|
|
27
95
|
<% } else if (it.inlineDisposition && it.inlineDisposition.kind === 'none-in-diff') { %>
|
|
28
96
|
โ No inline comments โ all findings are outside the diff (listed below).
|
|
29
|
-
<% } else if (it.inlineDisposition && it.inlineDisposition.kind === '
|
|
30
|
-
โ Inline
|
|
97
|
+
<% } else if (it.inlineDisposition && it.inlineDisposition.kind === 'inline-unavailable') { %>
|
|
98
|
+
โ โ ๏ธ Inline comments couldn't be posted for this review (GitHub rejected a comment's position) โ every finding is listed below instead.
|
|
99
|
+
<% } else if (it.inlineDisposition && it.inlineDisposition.kind === 'whole-document') { %>
|
|
100
|
+
โ This run's <%= it.incomplete ? 'review record' : 'complete review' %><% if (it.reviewUrl) { %> โ [see the review](<%~ it.reviewUrl %>)<% } %>.
|
|
31
101
|
<% } %>
|
|
32
102
|
|
|
33
103
|
<% if (it.strays.length > 0) { %>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
104
|
+
## <% if (it.inlineDisposition && (it.inlineDisposition.kind === 'disabled' || it.inlineDisposition.kind === 'whole-document')) { %>Findings<% } else if (it.inlineDisposition && it.inlineDisposition.kind === 'no-envelope') { %>Findings (no inline review โ result envelope lost)<% } else { %><%= (it.unanchoredCount && it.unanchoredCount > 0) ? 'Findings' : 'Findings outside the diff' %><% } %>
|
|
105
|
+
<% if (it.inlineDisposition && it.inlineDisposition.kind === 'no-envelope') { %>
|
|
106
|
+
_Every finding is listed below โ the inline review could not be built because the result envelope was missing._
|
|
107
|
+
<% } else if (it.inlineDisposition && it.inlineDisposition.kind === 'whole-document') { %>
|
|
108
|
+
_Every finding from this run<% if (it.inlineDisposition.inlineCount > 0) { %>, including the <%= it.inlineDisposition.inlineCount %> posted as inline comment<%= it.inlineDisposition.inlineCount === 1 ? '' : 's' %> on the diff<% } %><% if (it.inlineDisposition.rejectedCount > 0) { %>; <%= it.inlineDisposition.rejectedCount %> could not be anchored (GitHub rejected the position)<% } %>._
|
|
109
|
+
<% } else if (it.unanchoredCount && it.unanchoredCount > 0) { %>
|
|
110
|
+
_<%= it.unanchoredCount %> finding<%= it.unanchoredCount === 1 ? '' : 's' %> below couldn't be posted as inline comment<%= it.unanchoredCount === 1 ? '' : 's' %> (GitHub rejected the position)<% if (it.strays.length > it.unanchoredCount) { %>; the rest are outside the diff<% } %>._
|
|
111
|
+
<% } %>
|
|
37
112
|
|
|
38
113
|
<% it.strays.forEach(function(f) { -%>
|
|
39
|
-
|
|
40
|
-
<% if (f.
|
|
41
|
-
|
|
114
|
+
### <%= it.severityEmoji(f.severity) %> (<%= f.severity %>) `<%= f.path %>:<%= f.rangeLabel %><% if (f.side) { %> (<%= f.side %>)<% } %>` โ <%= f.title %>
|
|
115
|
+
<sub>confidence <%= it.formatConfidence(f.confidence) %> ยท likelihood <%= it.formatConfidence(f.likelihood) %><% if (f.id) { %> ยท id <% if (f.code_url) { %>[`<%~ f.id %>`](<%~ f.code_url %>)<% } else { %>`<%~ f.id %>`<% } %><% } %></sub>
|
|
116
|
+
<% if (f.permalink) { -%>
|
|
117
|
+
|
|
118
|
+
<%~ f.permalink %><% if (f.permalinkAnchored) { %> ยท _agent-reported location_<% } %>
|
|
119
|
+
<% } -%>
|
|
42
120
|
|
|
121
|
+
<%~ f.description %>
|
|
122
|
+
<% if (it.sameRootNotes && Object.prototype.hasOwnProperty.call(it.sameRootNotes, f.idKey)) { -%>
|
|
123
|
+
|
|
124
|
+
> โ ๏ธ <%~ it.sameRootNotes[f.idKey] %>
|
|
125
|
+
<% } -%>
|
|
126
|
+
<% if (f.answeredNote) { -%>
|
|
127
|
+
|
|
128
|
+
> โฉ๏ธ <%~ f.answeredNote %>
|
|
129
|
+
<% } -%>
|
|
130
|
+
<% if (f.recommendation) { -%>
|
|
131
|
+
|
|
132
|
+
**Recommended fix:** <%~ f.recommendation %>
|
|
133
|
+
<% } -%>
|
|
134
|
+
<% if (f.patchProjection.kind === "suggestion") { -%>
|
|
135
|
+
|
|
136
|
+
```suggestion
|
|
137
|
+
<%~ f.patchProjection.text %>
|
|
138
|
+
```
|
|
139
|
+
<% } else if (f.patchProjection.kind === "patch") { -%>
|
|
140
|
+
|
|
141
|
+
```patch
|
|
142
|
+
<%~ f.patchProjection.raw %>
|
|
143
|
+
```
|
|
144
|
+
<% } -%>
|
|
145
|
+
<% if (f.discussionHtml) { -%>
|
|
146
|
+
|
|
147
|
+
<details><summary>๐ฌ Discussion</summary>
|
|
148
|
+
|
|
149
|
+
<%~ f.discussionHtml %>
|
|
150
|
+
</details>
|
|
151
|
+
<% } -%>
|
|
152
|
+
|
|
153
|
+
> <details><summary>Reasoning</summary>
|
|
154
|
+
>
|
|
43
155
|
<% f.reasoning.split("\n").forEach(function(rl) { -%>
|
|
44
|
-
|
|
156
|
+
> <%= rl %>
|
|
157
|
+
<% }) -%>
|
|
158
|
+
>
|
|
159
|
+
> </details>
|
|
160
|
+
<% }) %>
|
|
161
|
+
<% } %>
|
|
162
|
+
|
|
163
|
+
<% if (it.discussionDropped > 0) { %>
|
|
164
|
+
_<%= it.discussionDropped %> discussion thread<%= it.discussionDropped === 1 ? '' : 's' %> not listed<% if ((it.discussionDroppedIds && it.discussionDroppedIds.length > 0) || (it.discussionDroppedSystemicIds && it.discussionDroppedSystemicIds.length > 0) || (it.discussionDroppedOrphanedIds && it.discussionDroppedOrphanedIds.length > 0)) { %> (<% if (it.discussionDroppedIds && it.discussionDroppedIds.length > 0) { %>finding<%= it.discussionDroppedIds.length === 1 ? '' : 's' %> <% it.discussionDroppedIds.forEach(function(id) { %>`<%~ id %>` <% }) %><% if ((it.discussionDroppedSystemicIds && it.discussionDroppedSystemicIds.length > 0) || (it.discussionDroppedOrphanedIds && it.discussionDroppedOrphanedIds.length > 0)) { %>ยท <% } %><% } %><% if (it.discussionDroppedSystemicIds && it.discussionDroppedSystemicIds.length > 0) { %>systemic<%= it.discussionDroppedSystemicIds.length === 1 ? '' : 's' %> <% it.discussionDroppedSystemicIds.forEach(function(id) { %>`<%~ id %>` <% }) %><% if (it.discussionDroppedOrphanedIds && it.discussionDroppedOrphanedIds.length > 0) { %>ยท <% } %><% } %><% if (it.discussionDroppedOrphanedIds && it.discussionDroppedOrphanedIds.length > 0) { %>earlier-round<% if (it.discussionDroppedOrphanedIds.length > 1) { %> (ร<%= it.discussionDroppedOrphanedIds.length %>)<% } %> <% it.discussionDroppedOrphanedIds.forEach(function(id) { %>`<%~ id %>` <% }) %><% } %>)<% } %><% if (it.discussionDroppedExtra > 0) { %> +<%= it.discussionDroppedExtra %> more<% } %> โ the links live on the comment thread._
|
|
165
|
+
<% } %>
|
|
166
|
+
|
|
167
|
+
<% if ((it.orphanedLines && it.orphanedLines.length > 0) || it.orphanedUnresolvable) { %>
|
|
168
|
+
## ๐ฌ Discussions on findings from earlier rounds
|
|
169
|
+
|
|
170
|
+
<% if (it.orphanedUnresolvable && (!it.orphanedLines || it.orphanedLines.length === 0)) { %>
|
|
171
|
+
_Comments naming tokens outside this round's report could not be matched against the prior findings โ the prior findings artifact could not be resolved, so whether they name departed findings is unknown._
|
|
172
|
+
<% } else { %>
|
|
173
|
+
<details><summary>Comments naming findings this round no longer reports (fixed or re-id'd) โ the conversation stays discoverable.<% if (it.orphanedTotal > it.orphanedLines.length) { %> (showing <%= it.orphanedLines.length %> of <%= it.orphanedTotal %>)<% } %></summary>
|
|
174
|
+
|
|
175
|
+
<% it.orphanedLines.forEach(function(line) { -%>
|
|
176
|
+
<%~ line %>
|
|
45
177
|
<% }) -%>
|
|
46
178
|
|
|
47
|
-
|
|
179
|
+
</details>
|
|
180
|
+
<% } %>
|
|
181
|
+
<% } %>
|
|
182
|
+
|
|
183
|
+
<% if (it.suppressedNits && it.suppressedNits.length > 0) { %>
|
|
184
|
+
> [!NOTE]
|
|
185
|
+
> <details><summary>๐ <%= it.suppressedNits.length %> nit<%= it.suppressedNits.length === 1 ? '' : 's' %> below the visibility floor (confidence ร likelihood < <%= it.nitVisibilityFloor %>) โ hidden</summary>
|
|
186
|
+
>
|
|
187
|
+
<% it.suppressedNits.forEach(function(n) { -%>
|
|
188
|
+
> - `<%= n.path %>:<%= n.startLine %>` โ <%= n.title %><% if (n.id) { %> (<% if (n.codeUrl) { %>[`<%~ n.id %>`](<%~ n.codeUrl %>)<% } else { %>`<%~ n.id %>`<% } %>)<% } %> _(m = <%= n.m %>)_
|
|
189
|
+
<% if (n.discussionHtml) { %><%~ n.discussionHtml %><% } %>
|
|
190
|
+
> <%~ '<!-- code-review:suppressed-nit' %>
|
|
191
|
+
> <%~ 'severity: ' + n.severity %>
|
|
192
|
+
> <%~ 'location: ' + n.path + ':' + n.startLine + '-' + n.endLine + (n.side ? ' (' + n.side + ')' : '') %>
|
|
193
|
+
> <%~ 'confidence: ' + n.confidence + ' \u00b7 likelihood: ' + n.likelihood %>
|
|
194
|
+
<% n.carried.forEach(function(cl) { -%>
|
|
195
|
+
> <%~ cl %>
|
|
196
|
+
<% }) -%>
|
|
197
|
+
> <%~ '-->' %>
|
|
198
|
+
<% }) -%>
|
|
199
|
+
<% if (it.carriedDroppedNits > 0) { -%>
|
|
200
|
+
> <%~ '<!-- code-review:suppressed-nit ' + it.carriedDroppedNits + ' nit(s) dropped from the sticky โ their findings are in the artifact -->' %>
|
|
48
201
|
<% } -%>
|
|
49
|
-
|
|
202
|
+
>
|
|
203
|
+
> </details>
|
|
50
204
|
<% } %>
|
|
51
205
|
|
|
52
206
|
<% if (it.testReport) { %>
|
|
@@ -83,5 +237,9 @@ All <%= it.testReport.total %> tests passed.
|
|
|
83
237
|
<% } else { -%>
|
|
84
238
|
> **Usage/cost unavailable** โ the result envelope for this run was missing or malformed.
|
|
85
239
|
<% } -%>
|
|
240
|
+
<% if (it.usageAvailable && !it.pricesProvided) { -%>
|
|
241
|
+
>
|
|
242
|
+
> _Cost shown as **N/A** โ [No `.github/prices.json`](https://github.com/JPHutchins/code-review/blob/main/schema/prices.example.json) price map to recompute from._
|
|
243
|
+
<% } -%>
|
|
86
244
|
>
|
|
87
245
|
> _Generated by [code-review](https://github.com/JPHutchins/code-review)<% if (it.runUrl) { %> ยท [view the run & traces](<%~ it.runUrl %>)<% } %>._
|
package/templates/inline.eta
CHANGED
|
@@ -1,19 +1,35 @@
|
|
|
1
|
-
<% if (it.
|
|
2
|
-
|
|
1
|
+
<% if (it.findingsPointer) { -%>
|
|
2
|
+
<%~ it.findingsPointer %>
|
|
3
3
|
<% } -%>
|
|
4
|
-
<%= it.severityEmoji(it.severity) %>
|
|
4
|
+
<%= it.severityEmoji(it.severity) %> <%= it.severity.charAt(0).toUpperCase() + it.severity.slice(1) %>: **<%= it.title %>** ยท <%= it.formatConfidence(it.confidence) %> confidence ยท <%= it.formatConfidence(it.likelihood) %> likelihood
|
|
5
5
|
|
|
6
|
-
<%~ it.
|
|
7
|
-
<% if (it.
|
|
6
|
+
<%~ it.description %>
|
|
7
|
+
<% if (it.sameRootNote) { -%>
|
|
8
|
+
|
|
9
|
+
> โ ๏ธ <%~ it.sameRootNote %>
|
|
10
|
+
<% } -%>
|
|
11
|
+
<% if (it.answeredNote) { -%>
|
|
12
|
+
|
|
13
|
+
> โฉ๏ธ <%~ it.answeredNote %>
|
|
14
|
+
<% } -%>
|
|
15
|
+
<% if (it.recommendation) { -%>
|
|
16
|
+
|
|
17
|
+
**Recommended fix:** <%~ it.recommendation %>
|
|
18
|
+
<% } -%>
|
|
19
|
+
<% if (it.patchProjection.kind === "suggestion") { -%>
|
|
8
20
|
|
|
9
21
|
```suggestion
|
|
10
|
-
<%~ it.
|
|
22
|
+
<%~ it.patchProjection.text %>
|
|
23
|
+
```
|
|
24
|
+
<% } else if (it.patchProjection.kind === "patch") { -%>
|
|
25
|
+
|
|
26
|
+
```patch
|
|
27
|
+
<%~ it.patchProjection.raw %>
|
|
11
28
|
```
|
|
12
29
|
<% } -%>
|
|
13
30
|
|
|
14
31
|
> [!TIP]
|
|
15
|
-
> Generated by <%~ it.modelsText
|
|
16
|
-
<% if (it.reasoning) { -%>
|
|
32
|
+
> Generated by <%~ it.modelsText %>.
|
|
17
33
|
> <details>
|
|
18
34
|
> <summary>Reasoning</summary>
|
|
19
35
|
>
|
|
@@ -22,4 +38,3 @@
|
|
|
22
38
|
<% }) -%>
|
|
23
39
|
>
|
|
24
40
|
> </details>
|
|
25
|
-
<% } -%>
|