@in-the-loop-labs/pair-review 2.3.3 → 2.4.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/.pi/skills/review-model-guidance/SKILL.md +1 -1
- package/.pi/skills/review-roulette/SKILL.md +1 -1
- package/README.md +15 -1
- package/package.json +2 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/review-requests/SKILL.md +1 -1
- package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
- package/public/css/pr.css +287 -14
- package/public/index.html +121 -57
- package/public/js/components/AIPanel.js +2 -1
- package/public/js/components/AdvancedConfigTab.js +2 -2
- package/public/js/components/AnalysisConfigModal.js +2 -2
- package/public/js/components/ChatPanel.js +187 -28
- package/public/js/components/CouncilProgressModal.js +4 -7
- package/public/js/components/SplitButton.js +66 -1
- package/public/js/components/VoiceCentricConfigTab.js +2 -2
- package/public/js/index.js +274 -21
- package/public/js/pr.js +194 -5
- package/public/local.html +8 -1
- package/public/pr.html +17 -2
- package/src/ai/codex-provider.js +14 -2
- package/src/ai/copilot-provider.js +1 -10
- package/src/ai/cursor-agent-provider.js +1 -10
- package/src/ai/gemini-provider.js +8 -17
- package/src/chat/acp-bridge.js +442 -0
- package/src/chat/api-reference.js +539 -0
- package/src/chat/chat-providers.js +290 -0
- package/src/chat/claude-code-bridge.js +499 -0
- package/src/chat/codex-bridge.js +601 -0
- package/src/chat/pi-bridge.js +56 -3
- package/src/chat/prompt-builder.js +12 -11
- package/src/chat/session-manager.js +110 -29
- package/src/config.js +4 -2
- package/src/database.js +50 -2
- package/src/github/client.js +43 -0
- package/src/routes/chat.js +60 -27
- package/src/routes/config.js +24 -1
- package/src/routes/github-collections.js +126 -0
- package/src/routes/mcp.js +2 -1
- package/src/routes/pr.js +166 -2
- package/src/routes/reviews.js +2 -1
- package/src/routes/shared.js +70 -49
- package/src/server.js +27 -1
- package/src/utils/safe-parse-json.js +19 -0
- package/.pi/skills/pair-review-api/SKILL.md +0 -448
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* API Reference Module
|
|
4
|
+
*
|
|
5
|
+
* Provides two views of the pair-review HTTP API:
|
|
6
|
+
* 1. renderApiDocs — full markdown reference with curl examples
|
|
7
|
+
* 2. buildApiCheatSheet — compact endpoint-only cheat sheet (~2KB, budget < 2.5KB)
|
|
8
|
+
*
|
|
9
|
+
* Both substitute real port and reviewId values into the output.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Full API reference markdown, derived from the SKILL.md specification.
|
|
14
|
+
* Placeholders {{PORT}} and {{REVIEW_ID}} are replaced with real values.
|
|
15
|
+
* @param {Object} options
|
|
16
|
+
* @param {number|string} options.port - Server port
|
|
17
|
+
* @param {number|string} options.reviewId - Current review ID
|
|
18
|
+
* @returns {string} Complete API reference in markdown
|
|
19
|
+
*/
|
|
20
|
+
function renderApiDocs({ port, reviewId }) {
|
|
21
|
+
if (reviewId == null) {
|
|
22
|
+
throw new Error('reviewId is required for renderApiDocs');
|
|
23
|
+
}
|
|
24
|
+
if (port == null) {
|
|
25
|
+
throw new Error('port is required for renderApiDocs');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return API_DOCS_TEMPLATE
|
|
29
|
+
.replace(/\{\{PORT\}\}/g, String(port))
|
|
30
|
+
.replace(/\{\{REVIEW_ID\}\}/g, String(reviewId));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Compact cheat sheet with endpoint signatures and key params.
|
|
35
|
+
* Under 2.5KB total, with real port/reviewId baked in.
|
|
36
|
+
* @param {Object} options
|
|
37
|
+
* @param {number|string} options.port - Server port
|
|
38
|
+
* @param {number|string} options.reviewId - Current review ID
|
|
39
|
+
* @returns {string} Cheat sheet in markdown
|
|
40
|
+
*/
|
|
41
|
+
function buildApiCheatSheet({ port, reviewId }) {
|
|
42
|
+
if (reviewId == null) {
|
|
43
|
+
throw new Error('reviewId is required for buildApiCheatSheet');
|
|
44
|
+
}
|
|
45
|
+
if (port == null) {
|
|
46
|
+
throw new Error('port is required for buildApiCheatSheet');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return CHEAT_SHEET_TEMPLATE
|
|
50
|
+
.replace(/\{\{PORT\}\}/g, String(port))
|
|
51
|
+
.replace(/\{\{REVIEW_ID\}\}/g, String(reviewId));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Templates
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
const API_DOCS_TEMPLATE = `# pair-review API Reference
|
|
59
|
+
|
|
60
|
+
## Comments
|
|
61
|
+
|
|
62
|
+
All comment operations use a single set of unified endpoints.
|
|
63
|
+
|
|
64
|
+
### List all comments
|
|
65
|
+
|
|
66
|
+
\`\`\`bash
|
|
67
|
+
curl -s http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
Optional query param: \`includeDismissed=true\` to include soft-deleted (inactive) comments.
|
|
71
|
+
|
|
72
|
+
**Response:** \`{ "success": true, "comments": [...] }\`
|
|
73
|
+
|
|
74
|
+
### Create a comment
|
|
75
|
+
|
|
76
|
+
A single endpoint handles both line-level and file-level comments. If \`line_start\` is present, it creates a line-level comment; if omitted, it creates a file-level comment.
|
|
77
|
+
|
|
78
|
+
**Line-level comment:**
|
|
79
|
+
\`\`\`bash
|
|
80
|
+
curl -s -X POST http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments \\
|
|
81
|
+
-H 'Content-Type: application/json' \\
|
|
82
|
+
-d '{
|
|
83
|
+
"file": "src/example.js",
|
|
84
|
+
"line_start": 42,
|
|
85
|
+
"line_end": 42,
|
|
86
|
+
"side": "right",
|
|
87
|
+
"body": "This variable should be renamed for clarity.",
|
|
88
|
+
"type": "suggestion",
|
|
89
|
+
"title": "Rename variable"
|
|
90
|
+
}'
|
|
91
|
+
\`\`\`
|
|
92
|
+
|
|
93
|
+
**File-level comment (omit \`line_start\`):**
|
|
94
|
+
\`\`\`bash
|
|
95
|
+
curl -s -X POST http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments \\
|
|
96
|
+
-H 'Content-Type: application/json' \\
|
|
97
|
+
-d '{
|
|
98
|
+
"file": "src/example.js",
|
|
99
|
+
"body": "This file needs better error handling throughout.",
|
|
100
|
+
"type": "suggestion",
|
|
101
|
+
"title": "Error handling"
|
|
102
|
+
}'
|
|
103
|
+
\`\`\`
|
|
104
|
+
|
|
105
|
+
**Response:** \`{ "success": true, "commentId": 123, "message": "Comment saved successfully" }\`
|
|
106
|
+
|
|
107
|
+
Required fields: \`file\`, \`body\`.
|
|
108
|
+
Optional fields: \`line_start\`, \`line_end\`, \`side\` ("left" or "right"), \`diff_position\`, \`commit_sha\`, \`parent_id\`, \`type\`, \`title\`.
|
|
109
|
+
|
|
110
|
+
### Get a single comment
|
|
111
|
+
|
|
112
|
+
\`\`\`bash
|
|
113
|
+
curl -s http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments/COMMENT_ID
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
### Update a comment
|
|
117
|
+
|
|
118
|
+
\`\`\`bash
|
|
119
|
+
curl -s -X PUT http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments/COMMENT_ID \\
|
|
120
|
+
-H 'Content-Type: application/json' \\
|
|
121
|
+
-d '{ "body": "Updated comment text." }'
|
|
122
|
+
\`\`\`
|
|
123
|
+
|
|
124
|
+
**Response:** \`{ "success": true, "message": "Comment updated successfully" }\`
|
|
125
|
+
|
|
126
|
+
### Delete a comment
|
|
127
|
+
|
|
128
|
+
> **Terminology note:** The UI refers to this operation as "dismiss." When a user asks to "dismiss a comment," use this DELETE endpoint.
|
|
129
|
+
|
|
130
|
+
Soft-deletes the comment. If the comment was adopted from an AI suggestion, the parent suggestion is automatically transitioned to "dismissed" status.
|
|
131
|
+
|
|
132
|
+
\`\`\`bash
|
|
133
|
+
curl -s -X DELETE http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments/COMMENT_ID
|
|
134
|
+
\`\`\`
|
|
135
|
+
|
|
136
|
+
**Response:** \`{ "success": true, "message": "Comment deleted successfully", "dismissedSuggestionId": null }\`
|
|
137
|
+
|
|
138
|
+
### Restore a deleted comment
|
|
139
|
+
|
|
140
|
+
\`\`\`bash
|
|
141
|
+
curl -s -X PUT http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments/COMMENT_ID/restore
|
|
142
|
+
\`\`\`
|
|
143
|
+
|
|
144
|
+
**Response:** \`{ "success": true, "message": "Comment restored successfully", "comment": {...} }\`
|
|
145
|
+
|
|
146
|
+
### Bulk delete all comments
|
|
147
|
+
|
|
148
|
+
Deletes all user comments for a review. Also dismisses any parent AI suggestions.
|
|
149
|
+
|
|
150
|
+
\`\`\`bash
|
|
151
|
+
curl -s -X DELETE http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/comments
|
|
152
|
+
\`\`\`
|
|
153
|
+
|
|
154
|
+
**Response:** \`{ "success": true, "deletedCount": 5, "dismissedSuggestionIds": [...], "message": "Deleted 5 user comments" }\`
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Suggestions
|
|
159
|
+
|
|
160
|
+
All suggestion operations use unified endpoints. These work identically for both PR and local reviews.
|
|
161
|
+
|
|
162
|
+
### List AI suggestions
|
|
163
|
+
|
|
164
|
+
\`\`\`bash
|
|
165
|
+
curl -s 'http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/suggestions'
|
|
166
|
+
\`\`\`
|
|
167
|
+
|
|
168
|
+
Optional query params:
|
|
169
|
+
- \`levels\` — comma-separated list of levels: \`"final"\`, \`"1"\`, \`"2"\`, \`"3"\`. Default: \`"final"\` (orchestrated suggestions only).
|
|
170
|
+
- \`runId\` — specific analysis run UUID. Default: latest run.
|
|
171
|
+
|
|
172
|
+
**Response:** \`{ "suggestions": [{ "id": 1, "file": "...", "line_start": 10, "type": "bug", "title": "...", "body": "...", "status": "active", ... }] }\`
|
|
173
|
+
|
|
174
|
+
### Check if suggestions exist
|
|
175
|
+
|
|
176
|
+
\`\`\`bash
|
|
177
|
+
curl -s 'http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/suggestions/check'
|
|
178
|
+
\`\`\`
|
|
179
|
+
|
|
180
|
+
Optional query param: \`runId\` (specific analysis run UUID).
|
|
181
|
+
|
|
182
|
+
**Response:** \`{ "hasSuggestions": true, "analysisHasRun": true, "summary": "...", "stats": { "issues": 2, "suggestions": 3, "praise": 1 } }\`
|
|
183
|
+
|
|
184
|
+
### Update AI suggestion status
|
|
185
|
+
|
|
186
|
+
\`\`\`bash
|
|
187
|
+
curl -s -X POST http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/suggestions/SUGGESTION_ID/status \\
|
|
188
|
+
-H 'Content-Type: application/json' \\
|
|
189
|
+
-d '{ "status": "dismissed" }'
|
|
190
|
+
\`\`\`
|
|
191
|
+
|
|
192
|
+
Valid statuses: \`"dismissed"\`, \`"active"\` (restore).
|
|
193
|
+
|
|
194
|
+
> **Note:** Setting status to \`"adopted"\` directly is not allowed. Adoption must create a linked user comment via \`parent_id\`, which is why raw status-setting cannot do it. Use \`POST /suggestions/:id/adopt\` for adopt-as-is or \`POST /suggestions/:id/edit\` for adopt-with-edits.
|
|
195
|
+
|
|
196
|
+
**Response:** \`{ "success": true, "status": "dismissed" }\`
|
|
197
|
+
|
|
198
|
+
### Adopt an AI suggestion as-is
|
|
199
|
+
|
|
200
|
+
Atomically creates a user comment from the suggestion's body/type/title (with category prefix), sets \`parent_id\` linkage, and updates suggestion status to \`adopted\`.
|
|
201
|
+
|
|
202
|
+
\`\`\`bash
|
|
203
|
+
curl -s -X POST http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/suggestions/SUGGESTION_ID/adopt
|
|
204
|
+
\`\`\`
|
|
205
|
+
|
|
206
|
+
No request body required.
|
|
207
|
+
|
|
208
|
+
**Response:** \`{ "success": true, "userCommentId": 124, "message": "Suggestion adopted as user comment" }\`
|
|
209
|
+
|
|
210
|
+
### Adopt an AI suggestion with edits
|
|
211
|
+
|
|
212
|
+
Edits the suggestion text and adopts it as a new user comment.
|
|
213
|
+
|
|
214
|
+
\`\`\`bash
|
|
215
|
+
curl -s -X POST http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/suggestions/SUGGESTION_ID/edit \\
|
|
216
|
+
-H 'Content-Type: application/json' \\
|
|
217
|
+
-d '{
|
|
218
|
+
"action": "adopt_edited",
|
|
219
|
+
"editedText": "The edited comment body to adopt as a user comment."
|
|
220
|
+
}'
|
|
221
|
+
\`\`\`
|
|
222
|
+
|
|
223
|
+
**Response:** \`{ "success": true, "userCommentId": 125, "message": "Suggestion edited and adopted as user comment" }\`
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Analysis Launch
|
|
228
|
+
|
|
229
|
+
Analysis launch endpoints are **mode-specific** because starting an analysis requires mode-specific context (worktree paths for PRs, local directory paths for local reviews). Once launched, all subsequent analysis management uses the shared endpoints below.
|
|
230
|
+
|
|
231
|
+
### Trigger AI analysis (PR mode)
|
|
232
|
+
|
|
233
|
+
\`\`\`bash
|
|
234
|
+
curl -s -X POST http://localhost:{{PORT}}/api/pr/OWNER/REPO/PR_NUMBER/analyses \\
|
|
235
|
+
-H 'Content-Type: application/json' \\
|
|
236
|
+
-d '{
|
|
237
|
+
"provider": "claude",
|
|
238
|
+
"model": "claude-sonnet-4-5-20250929",
|
|
239
|
+
"tier": "balanced",
|
|
240
|
+
"customInstructions": "Focus on security issues."
|
|
241
|
+
}'
|
|
242
|
+
\`\`\`
|
|
243
|
+
|
|
244
|
+
### Trigger AI analysis (local mode)
|
|
245
|
+
|
|
246
|
+
\`\`\`bash
|
|
247
|
+
curl -s -X POST http://localhost:{{PORT}}/api/local/{{REVIEW_ID}}/analyses \\
|
|
248
|
+
-H 'Content-Type: application/json' \\
|
|
249
|
+
-d '{
|
|
250
|
+
"provider": "claude",
|
|
251
|
+
"tier": "balanced",
|
|
252
|
+
"customInstructions": "Focus on security issues."
|
|
253
|
+
}'
|
|
254
|
+
\`\`\`
|
|
255
|
+
|
|
256
|
+
**Response (both modes):** \`{ "analysisId": "uuid", "runId": "uuid", "status": "started", "message": "AI analysis started in background" }\`
|
|
257
|
+
|
|
258
|
+
Optional body fields: \`provider\`, \`model\`, \`tier\` ("fast", "balanced", "thorough"), \`customInstructions\`, \`skipLevel3\` (boolean), \`enabledLevels\` (object like \`{"1": true, "2": true, "3": false}\`).
|
|
259
|
+
|
|
260
|
+
### Trigger council analysis (PR mode)
|
|
261
|
+
|
|
262
|
+
\`\`\`bash
|
|
263
|
+
curl -s -X POST http://localhost:{{PORT}}/api/pr/OWNER/REPO/PR_NUMBER/analyses/council \\
|
|
264
|
+
-H 'Content-Type: application/json' \\
|
|
265
|
+
-d '{
|
|
266
|
+
"councilId": "COUNCIL_UUID",
|
|
267
|
+
"customInstructions": "Focus on security."
|
|
268
|
+
}'
|
|
269
|
+
\`\`\`
|
|
270
|
+
|
|
271
|
+
### Trigger council analysis (local mode)
|
|
272
|
+
|
|
273
|
+
\`\`\`bash
|
|
274
|
+
curl -s -X POST http://localhost:{{PORT}}/api/local/{{REVIEW_ID}}/analyses/council \\
|
|
275
|
+
-H 'Content-Type: application/json' \\
|
|
276
|
+
-d '{
|
|
277
|
+
"councilId": "COUNCIL_UUID",
|
|
278
|
+
"customInstructions": "Focus on security."
|
|
279
|
+
}'
|
|
280
|
+
\`\`\`
|
|
281
|
+
|
|
282
|
+
**Response (both modes):** \`{ "analysisId": "uuid", "runId": "uuid", "status": "started", "message": "Council analysis started in background", "isCouncil": true }\`
|
|
283
|
+
|
|
284
|
+
Required: either \`councilId\` (UUID of a saved council config) or \`councilConfig\` (inline config object).
|
|
285
|
+
Optional: \`customInstructions\`, \`configType\` ("advanced" or "council").
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Analysis Status (Review-Level)
|
|
290
|
+
|
|
291
|
+
Check whether an analysis is currently running for a review. This is a unified endpoint that works for both PR and local reviews.
|
|
292
|
+
|
|
293
|
+
\`\`\`bash
|
|
294
|
+
curl -s http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/analyses/status
|
|
295
|
+
\`\`\`
|
|
296
|
+
|
|
297
|
+
**Response (running):** \`{ "running": true, "analysisId": "uuid", "status": {...} }\`
|
|
298
|
+
**Response (idle):** \`{ "running": false, "analysisId": null, "status": null }\`
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Analysis Management
|
|
303
|
+
|
|
304
|
+
These shared endpoints operate on analysis UUIDs (returned when you launch an analysis). They work for both PR and local reviews.
|
|
305
|
+
|
|
306
|
+
### Get analysis status by ID
|
|
307
|
+
|
|
308
|
+
\`\`\`bash
|
|
309
|
+
curl -s http://localhost:{{PORT}}/api/analyses/ANALYSIS_ID/status
|
|
310
|
+
\`\`\`
|
|
311
|
+
|
|
312
|
+
**Response:** \`{ "id": "...", "status": "running"|"completed"|"failed"|"cancelled", "levels": {...}, "progress": "...", ... }\`
|
|
313
|
+
|
|
314
|
+
### Cancel an analysis
|
|
315
|
+
|
|
316
|
+
\`\`\`bash
|
|
317
|
+
curl -s -X POST http://localhost:{{PORT}}/api/analyses/ANALYSIS_ID/cancel
|
|
318
|
+
\`\`\`
|
|
319
|
+
|
|
320
|
+
**Response:** \`{ "success": true, "message": "Analysis cancelled", "processesKilled": 2, "status": "cancelled" }\`
|
|
321
|
+
|
|
322
|
+
### Real-time progress (WebSocket)
|
|
323
|
+
|
|
324
|
+
Analysis progress is delivered via WebSocket, not HTTP polling.
|
|
325
|
+
|
|
326
|
+
1. Connect to \`ws://localhost:{{PORT}}/ws\`
|
|
327
|
+
2. Subscribe: \`{ "action": "subscribe", "topic": "analysis:ANALYSIS_ID" }\`
|
|
328
|
+
3. Receive progress events: \`{ "type": "progress", "topic": "analysis:ANALYSIS_ID", ... }\`
|
|
329
|
+
|
|
330
|
+
For simple polling, use \`GET /api/analyses/ANALYSIS_ID/status\` instead.
|
|
331
|
+
|
|
332
|
+
### List analysis runs for a review
|
|
333
|
+
|
|
334
|
+
\`\`\`bash
|
|
335
|
+
curl -s 'http://localhost:{{PORT}}/api/analyses/runs?reviewId={{REVIEW_ID}}'
|
|
336
|
+
\`\`\`
|
|
337
|
+
|
|
338
|
+
**Response:** \`{ "runs": [{ "id": "uuid", "review_id": 1, "provider": "claude", "status": "completed", ... }] }\`
|
|
339
|
+
|
|
340
|
+
### Get latest analysis run for a review
|
|
341
|
+
|
|
342
|
+
\`\`\`bash
|
|
343
|
+
curl -s 'http://localhost:{{PORT}}/api/analyses/runs/latest?reviewId={{REVIEW_ID}}'
|
|
344
|
+
\`\`\`
|
|
345
|
+
|
|
346
|
+
**Response:** \`{ "run": { "id": "uuid", "review_id": 1, "provider": "claude", "status": "completed", ... } }\`
|
|
347
|
+
|
|
348
|
+
### Get a specific analysis run by ID
|
|
349
|
+
|
|
350
|
+
\`\`\`bash
|
|
351
|
+
curl -s http://localhost:{{PORT}}/api/analyses/runs/RUN_ID
|
|
352
|
+
\`\`\`
|
|
353
|
+
|
|
354
|
+
**Response:** \`{ "run": { "id": "uuid", ... } }\`
|
|
355
|
+
|
|
356
|
+
### Import external analysis results
|
|
357
|
+
|
|
358
|
+
Submit analysis results produced outside pair-review (e.g., by a coding agent):
|
|
359
|
+
|
|
360
|
+
\`\`\`bash
|
|
361
|
+
curl -s -X POST http://localhost:{{PORT}}/api/analyses/results \\
|
|
362
|
+
-H 'Content-Type: application/json' \\
|
|
363
|
+
-d '{
|
|
364
|
+
"path": "/absolute/path/to/repo",
|
|
365
|
+
"headSha": "abc123",
|
|
366
|
+
"provider": "claude",
|
|
367
|
+
"summary": "Analysis summary text",
|
|
368
|
+
"suggestions": [
|
|
369
|
+
{
|
|
370
|
+
"file": "src/example.js",
|
|
371
|
+
"line_start": 10,
|
|
372
|
+
"line_end": 15,
|
|
373
|
+
"type": "bug",
|
|
374
|
+
"title": "Potential null reference",
|
|
375
|
+
"description": "This could throw if input is null."
|
|
376
|
+
}
|
|
377
|
+
],
|
|
378
|
+
"fileLevelSuggestions": []
|
|
379
|
+
}'
|
|
380
|
+
\`\`\`
|
|
381
|
+
|
|
382
|
+
Required: either \`path\` + \`headSha\` (local mode) or \`repo\` + \`prNumber\` (PR mode).
|
|
383
|
+
Each suggestion requires: \`file\`, \`type\`, \`title\`, \`description\`.
|
|
384
|
+
|
|
385
|
+
**Response (HTTP 201):** \`{ "runId": "uuid", "reviewId": 1, "totalSuggestions": 5, "status": "completed" }\`
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Comment Types
|
|
390
|
+
|
|
391
|
+
The \`type\` field on comments and suggestions can be one of:
|
|
392
|
+
- \`"bug"\` - Bug or defect
|
|
393
|
+
- \`"suggestion"\` - General suggestion
|
|
394
|
+
- \`"improvement"\` - Code improvement
|
|
395
|
+
- \`"security"\` - Security concern
|
|
396
|
+
- \`"performance"\` - Performance issue
|
|
397
|
+
- \`"design"\` - Design/architecture concern
|
|
398
|
+
- \`"praise"\` - Positive feedback
|
|
399
|
+
- \`"style"\` or \`"code-style"\` - Style/formatting
|
|
400
|
+
- \`"nitpick"\` - Minor nitpick
|
|
401
|
+
- \`"question"\` - Question for the author
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Context Files
|
|
406
|
+
|
|
407
|
+
Add non-diff files to the review's diff panel for reference during discussion. Each context file shows a specific line range from a file that isn't part of the PR/local changes.
|
|
408
|
+
|
|
409
|
+
### Add a context file
|
|
410
|
+
|
|
411
|
+
\`\`\`bash
|
|
412
|
+
curl -s -X POST http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/context-files \\
|
|
413
|
+
-H 'Content-Type: application/json' \\
|
|
414
|
+
-d '{
|
|
415
|
+
"file": "src/utils/helpers.js",
|
|
416
|
+
"line_start": 42,
|
|
417
|
+
"line_end": 78,
|
|
418
|
+
"label": "Helper function used by the changed code"
|
|
419
|
+
}'
|
|
420
|
+
\`\`\`
|
|
421
|
+
|
|
422
|
+
**Response (HTTP 201):** \`{ "success": true, "contextFile": { "id": 1, "review_id": 1, "file": "...", "line_start": 42, "line_end": 78, "label": "..." } }\`
|
|
423
|
+
|
|
424
|
+
Required fields: \`file\` (must be a relative path without \`..\` segments), \`line_start\`, \`line_end\`.
|
|
425
|
+
Optional fields: \`label\`.
|
|
426
|
+
|
|
427
|
+
### List context files
|
|
428
|
+
|
|
429
|
+
\`\`\`bash
|
|
430
|
+
curl -s http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/context-files
|
|
431
|
+
\`\`\`
|
|
432
|
+
|
|
433
|
+
**Response:** \`{ "success": true, "contextFiles": [...] }\`
|
|
434
|
+
|
|
435
|
+
### Remove a context file
|
|
436
|
+
|
|
437
|
+
\`\`\`bash
|
|
438
|
+
curl -s -X DELETE http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/context-files/CONTEXT_FILE_ID
|
|
439
|
+
\`\`\`
|
|
440
|
+
|
|
441
|
+
**Response:** \`{ "success": true, "message": "Context file removed" }\`
|
|
442
|
+
|
|
443
|
+
### Remove all context files
|
|
444
|
+
|
|
445
|
+
\`\`\`bash
|
|
446
|
+
curl -s -X DELETE http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/context-files
|
|
447
|
+
\`\`\`
|
|
448
|
+
|
|
449
|
+
**Response:** \`{ "success": true, "deletedCount": 3, "message": "Removed 3 context files" }\`
|
|
450
|
+
|
|
451
|
+
### Guidelines
|
|
452
|
+
|
|
453
|
+
- Use judiciously -- only add files that are directly relevant to the discussion.
|
|
454
|
+
- Keep ranges focused on specific functions/blocks (max 500 lines).
|
|
455
|
+
- Use the \`label\` field to explain why the file is relevant.
|
|
456
|
+
- Context files appear in the diff panel below the actual changes.
|
|
457
|
+
- Reference context files in chat using backtick notation: \`\` \`src/utils/helpers.js:42-78\` \`\`.
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Diff Hunk Expansion
|
|
462
|
+
|
|
463
|
+
Expand collapsed diff gaps to reveal hidden lines. Useful when you need to show the user lines that are inside a collapsed hunk. This is a transient UI command — expansions are not persisted.
|
|
464
|
+
|
|
465
|
+
### Expand a hunk
|
|
466
|
+
|
|
467
|
+
\`\`\`bash
|
|
468
|
+
curl -X POST http://localhost:{{PORT}}/api/reviews/{{REVIEW_ID}}/expand-hunk \\
|
|
469
|
+
-H "Content-Type: application/json" \\
|
|
470
|
+
-d '{
|
|
471
|
+
"file": "src/app.js",
|
|
472
|
+
"line_start": 10,
|
|
473
|
+
"line_end": 20,
|
|
474
|
+
"side": "right"
|
|
475
|
+
}'
|
|
476
|
+
\`\`\`
|
|
477
|
+
|
|
478
|
+
**Required fields:**
|
|
479
|
+
- \`file\` (string): Path of the changed file in the diff
|
|
480
|
+
- \`line_start\` (integer): First line to reveal (>= 1)
|
|
481
|
+
- \`line_end\` (integer): Last line to reveal (>= \`line_start\`)
|
|
482
|
+
|
|
483
|
+
**Optional fields:**
|
|
484
|
+
- \`side\` (string): \`"left"\` or \`"right"\` (default: \`"right"\`)
|
|
485
|
+
|
|
486
|
+
**Response:** \`{ "success": true }\``;
|
|
487
|
+
|
|
488
|
+
const CHEAT_SHEET_TEMPLATE = `# pair-review API Cheat Sheet
|
|
489
|
+
|
|
490
|
+
Full docs: \`curl http://localhost:{{PORT}}/api.md?reviewId={{REVIEW_ID}}\`
|
|
491
|
+
|
|
492
|
+
Base: \`http://localhost:{{PORT}}\` | Review: \`{{REVIEW_ID}}\`
|
|
493
|
+
|
|
494
|
+
## Comments — /api/reviews/{{REVIEW_ID}}/comments
|
|
495
|
+
- \`GET\` — List all (?includeDismissed=true)
|
|
496
|
+
- \`POST\` — Create {file, body, ?line_start, ?line_end, ?side, ?type, ?title} (no line_start=file-level)
|
|
497
|
+
- \`GET /:id\` — Get one
|
|
498
|
+
- \`PUT /:id\` — Update {body}
|
|
499
|
+
- \`DELETE /:id\` — Dismiss (soft-delete)
|
|
500
|
+
- \`PUT /:id/restore\` — Restore dismissed
|
|
501
|
+
- \`DELETE\` (no id) — Bulk dismiss all
|
|
502
|
+
|
|
503
|
+
## Suggestions — /api/reviews/{{REVIEW_ID}}/suggestions
|
|
504
|
+
- \`GET\` — List (?levels=final,1,2,3 &runId=UUID)
|
|
505
|
+
- \`GET /check\` — Exists? (?runId=UUID)
|
|
506
|
+
- \`POST /:id/status\` — Dismiss/restore {status}
|
|
507
|
+
- \`POST /:id/adopt\` — Adopt as-is (no body)
|
|
508
|
+
- \`POST /:id/edit\` — Adopt edited {action:"adopt_edited", editedText:"..."}
|
|
509
|
+
|
|
510
|
+
## Analysis Launch (mode-specific)
|
|
511
|
+
- \`POST /api/pr/:owner/:repo/:pr/analyses\` — PR analysis
|
|
512
|
+
- \`POST /api/local/{{REVIEW_ID}}/analyses\` — Local analysis
|
|
513
|
+
Body: {?provider, ?model, ?tier, ?customInstructions, ?skipLevel3, ?enabledLevels}
|
|
514
|
+
- \`POST .../analyses/council\` — Council (add /council to above)
|
|
515
|
+
Body: {councilId|councilConfig, ?customInstructions}
|
|
516
|
+
|
|
517
|
+
## Analysis Status & Management
|
|
518
|
+
- \`GET /api/reviews/{{REVIEW_ID}}/analyses/status\` — Running?
|
|
519
|
+
- \`GET /api/analyses/:id/status\` — Status by analysis ID
|
|
520
|
+
- \`POST /api/analyses/:id/cancel\` — Cancel
|
|
521
|
+
- WebSocket /ws: subscribe "analysis:{id}" for progress
|
|
522
|
+
- \`GET /api/analyses/runs?reviewId={{REVIEW_ID}}\` — List runs
|
|
523
|
+
- \`GET /api/analyses/runs/latest?reviewId={{REVIEW_ID}}\` — Latest run
|
|
524
|
+
- \`GET /api/analyses/runs/:id\` — Specific run
|
|
525
|
+
- \`POST /api/analyses/results\` — Import external results
|
|
526
|
+
|
|
527
|
+
## Context Files — /api/reviews/{{REVIEW_ID}}/context-files
|
|
528
|
+
- \`POST\` — Add {file, line_start, line_end, ?label}
|
|
529
|
+
- \`GET\` — List all
|
|
530
|
+
- \`DELETE /:id\` — Remove one
|
|
531
|
+
- \`DELETE\` (no id) — Remove all
|
|
532
|
+
|
|
533
|
+
## Diff Hunk Expansion
|
|
534
|
+
- \`POST /api/reviews/{{REVIEW_ID}}/expand-hunk\` — {file, line_start, line_end, ?side}
|
|
535
|
+
|
|
536
|
+
## Comment Types
|
|
537
|
+
bug | suggestion | improvement | security | performance | design | praise | style | nitpick | question`;
|
|
538
|
+
|
|
539
|
+
module.exports = { renderApiDocs, buildApiCheatSheet };
|