co-maintainer 0.4.13 → 0.5.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +57 -38
- package/dist/main.js +2 -3
- package/dist/package.json +21 -15
- package/dist/src/ai/batch.d.ts +24 -1
- package/dist/src/ai/batch.js +75 -23
- package/dist/src/ai/estimate.d.ts +40 -0
- package/dist/src/ai/estimate.js +113 -0
- package/dist/src/ai/fake.d.ts +1 -1
- package/dist/src/ai/fake.js +1 -1
- package/dist/src/ai/hetzner.js +1 -1
- package/dist/src/ai/openrouter.d.ts +13 -0
- package/dist/src/ai/openrouter.js +66 -12
- package/dist/src/ai/pricing.d.ts +14 -0
- package/dist/src/ai/pricing.js +77 -0
- package/dist/src/ai/provider.js +8 -0
- package/dist/src/ai/verify.d.ts +25 -0
- package/dist/src/ai/verify.js +78 -0
- package/dist/src/cli/args.js +25 -29
- package/dist/src/cli/commands/config.d.ts +44 -0
- package/dist/src/cli/commands/config.js +220 -0
- package/dist/src/cli/commands/probe.js +70 -103
- package/dist/src/cli/commands/registry.d.ts +57 -0
- package/dist/src/cli/commands/registry.js +713 -0
- package/dist/src/cli/commands/review.js +66 -43
- package/dist/src/cli/commands/serve.d.ts +4 -2
- package/dist/src/cli/commands/serve.js +14 -10
- package/dist/src/cli/commands/set.d.ts +2 -1
- package/dist/src/cli/commands/set.js +63 -17
- package/dist/src/cli/commands/view.d.ts +1 -0
- package/dist/src/cli/commands/view.js +180 -0
- package/dist/src/cli/error.d.ts +39 -0
- package/dist/src/cli/error.js +64 -0
- package/dist/src/cli/main.d.ts +7 -0
- package/dist/src/cli/main.js +82 -1
- package/dist/src/cli/prompt.js +21 -7
- package/dist/src/cli/review_args.d.ts +4 -0
- package/dist/src/cli/review_args.js +22 -9
- package/dist/src/cli/review_output.d.ts +2 -2
- package/dist/src/cli/review_output.js +7 -6
- package/dist/src/cli/review_result.d.ts +59 -8
- package/dist/src/cli/review_result.js +145 -103
- package/dist/src/config.d.ts +15 -0
- package/dist/src/config.js +31 -0
- package/dist/src/github/app.d.ts +13 -0
- package/dist/src/github/app.js +23 -0
- package/dist/src/github/app_manifest.d.ts +50 -0
- package/dist/src/github/app_manifest.js +138 -0
- package/dist/src/github/client.js +7 -1
- package/dist/src/github/collect.js +1 -1
- package/dist/src/github/gh.js +75 -18
- package/dist/src/knowledge/facts.js +8 -3
- package/dist/src/knowledge/guide.d.ts +8 -0
- package/dist/src/knowledge/guide.js +32 -8
- package/dist/src/knowledge/probe.js +13 -3
- package/dist/src/knowledge/sections.d.ts +9 -0
- package/dist/src/knowledge/sections.js +16 -0
- package/dist/src/knowledge/skill.d.ts +5 -0
- package/dist/src/knowledge/skill.js +68 -21
- package/dist/src/knowledge/synthesis.d.ts +17 -1
- package/dist/src/knowledge/synthesis.js +70 -15
- package/dist/src/knowledge/types.d.ts +5 -0
- package/dist/src/local/codegraph_prepare.d.ts +3 -2
- package/dist/src/local/codegraph_prepare.js +4 -2
- package/dist/src/local/git_ops.d.ts +5 -4
- package/dist/src/local/git_ops.js +8 -9
- package/dist/src/local/review_local.js +36 -14
- package/dist/src/pr/checkout.js +14 -3
- package/dist/src/pr/codegraph_tools.js +3 -3
- package/dist/src/pr/diff_summary.js +3 -3
- package/dist/src/pr/findings.js +16 -5
- package/dist/src/pr/findings_json.d.ts +26 -0
- package/dist/src/pr/findings_json.js +187 -0
- package/dist/src/pr/review_copy.d.ts +20 -0
- package/dist/src/pr/review_copy.js +40 -0
- package/dist/src/pr/reviewer.d.ts +2 -1
- package/dist/src/pr/reviewer.js +84 -91
- package/dist/src/remote/client.js +42 -42
- package/dist/src/remote/http.d.ts +5 -0
- package/dist/src/remote/http.js +49 -0
- package/dist/src/remote/server/guides.d.ts +22 -0
- package/dist/src/remote/server/guides.js +81 -0
- package/dist/src/remote/server/routes.js +24 -0
- package/dist/src/review/blocking.d.ts +35 -0
- package/dist/src/review/blocking.js +45 -0
- package/dist/src/review/carry_over.d.ts +12 -1
- package/dist/src/review/carry_over.js +35 -9
- package/dist/src/review/engine.d.ts +1 -0
- package/dist/src/review/guides.js +28 -1
- package/dist/src/server/api/installations.js +1 -1
- package/dist/src/server/api/repos.js +86 -3
- package/dist/src/server/api/settings.js +3 -3
- package/dist/src/server/app.d.ts +3 -0
- package/dist/src/server/app.js +12 -5
- package/dist/src/server/pages/activity.d.ts +1 -0
- package/dist/src/server/pages/activity.js +2 -2
- package/dist/src/server/pages/add_repo.js +73 -5
- package/dist/src/server/pages/client.d.ts +1 -1
- package/dist/src/server/pages/client.js +1 -1
- package/dist/src/server/pages/home.d.ts +6 -1
- package/dist/src/server/pages/home.js +25 -2
- package/dist/src/server/pages/knowledge.js +1 -1
- package/dist/src/server/pages/layout.js +2 -2
- package/dist/src/server/pages/repo.d.ts +1 -1
- package/dist/src/server/pages/repo.js +21 -2
- package/dist/src/server/pages/repo_prs.d.ts +5 -1
- package/dist/src/server/pages/repo_prs.js +36 -1
- package/dist/src/server/pages/repo_remote.js +2 -2
- package/dist/src/server/pages/repo_settings.js +2 -2
- package/dist/src/server/pages/router.d.ts +6 -0
- package/dist/src/server/pages/router.js +129 -9
- package/dist/src/server/pages/settings.d.ts +1 -1
- package/dist/src/server/pages/settings.js +87 -9
- package/dist/src/server/pages/styles.d.ts +1 -1
- package/dist/src/server/pages/styles.js +1 -1
- package/dist/src/services/probe.d.ts +28 -0
- package/dist/src/services/probe.js +133 -0
- package/dist/src/services/remake_cron.d.ts +1 -1
- package/dist/src/services/remake_cron.js +3 -3
- package/dist/src/services/remote_review.js +14 -4
- package/dist/src/services/review.d.ts +11 -0
- package/dist/src/services/review.js +39 -11
- package/dist/src/services/setup.js +37 -19
- package/dist/src/services/setup_checklist.d.ts +10 -0
- package/dist/src/services/setup_checklist.js +87 -0
- package/dist/src/store/app_db.js +5 -2
- package/dist/src/store/cache_db.d.ts +4 -0
- package/dist/src/store/cache_db.js +27 -4
- package/dist/src/store/deliveries.d.ts +7 -0
- package/dist/src/store/deliveries.js +15 -0
- package/dist/src/tools/codegraph.d.ts +30 -0
- package/dist/src/tools/codegraph.js +49 -12
- package/dist/src/types.d.ts +10 -0
- package/dist/src/util/log.d.ts +3 -0
- package/dist/src/util/log.js +12 -0
- package/dist/src/util/run_summary.d.ts +33 -0
- package/dist/src/util/run_summary.js +47 -0
- package/dist/src/util/webhook_reachability.d.ts +11 -0
- package/dist/src/util/webhook_reachability.js +64 -0
- package/package.json +21 -15
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
/** The command registry (CORE-20).
|
|
2
|
+
*
|
|
3
|
+
* One place that knows every command, its aliases, its usage lines, its flags
|
|
4
|
+
* and its examples. Everything the user reads as help is rendered from here,
|
|
5
|
+
* so a flag cannot drift out of the help and a command cannot be documented
|
|
6
|
+
* twice with different wording. It is also the source CORE-81 will export to
|
|
7
|
+
* the command reference, which is why it is data rather than template strings.
|
|
8
|
+
*/
|
|
9
|
+
const OUTPUT_FLAGS = {
|
|
10
|
+
title: "Output and diagnostics",
|
|
11
|
+
flags: [
|
|
12
|
+
{
|
|
13
|
+
name: "json",
|
|
14
|
+
description: "Print machine-readable JSON instead of prose.",
|
|
15
|
+
},
|
|
16
|
+
{ name: "debug", description: "Print the underlying gh and HTTP calls." },
|
|
17
|
+
{ name: "log-time", description: "Print how long each phase took." },
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
const AI_FLAGS = {
|
|
21
|
+
title: "AI",
|
|
22
|
+
flags: [
|
|
23
|
+
{
|
|
24
|
+
name: "ai",
|
|
25
|
+
value: "none|openrouter|hetzner",
|
|
26
|
+
default: "none",
|
|
27
|
+
description: "Which provider writes the review.",
|
|
28
|
+
},
|
|
29
|
+
{ name: "token", value: "KEY", description: "The provider API key." },
|
|
30
|
+
{
|
|
31
|
+
name: "ai-key",
|
|
32
|
+
value: "KEY",
|
|
33
|
+
description: "The same key as --token, named for what it is.",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "low-model",
|
|
37
|
+
value: "ID",
|
|
38
|
+
default: "openai/gpt-oss-120b",
|
|
39
|
+
description: "Model for extraction work.",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "high-model",
|
|
43
|
+
value: "ID",
|
|
44
|
+
default: "openai/gpt-5.6-luna",
|
|
45
|
+
description: "Model for the review itself.",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
const GITHUB_FLAGS = {
|
|
50
|
+
title: "GitHub access",
|
|
51
|
+
flags: [
|
|
52
|
+
{
|
|
53
|
+
name: "auth",
|
|
54
|
+
value: "gh|pat",
|
|
55
|
+
default: "gh",
|
|
56
|
+
description: "Use the gh CLI or a personal access token.",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "github-pat",
|
|
60
|
+
value: "TOKEN",
|
|
61
|
+
description: "The token when --auth=pat.",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
export const COMMANDS = [
|
|
66
|
+
{
|
|
67
|
+
name: "probe",
|
|
68
|
+
summary: "Inspect a repository and recommend the init flags for it.",
|
|
69
|
+
usage: ["co-maintainer probe owner/repo [options]"],
|
|
70
|
+
groups: [
|
|
71
|
+
GITHUB_FLAGS,
|
|
72
|
+
{
|
|
73
|
+
title: "Limits",
|
|
74
|
+
flags: [
|
|
75
|
+
{
|
|
76
|
+
name: "max-pull-request-change-lines",
|
|
77
|
+
value: "N",
|
|
78
|
+
description: "Cap the diff size sampled.",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "max-pr-months",
|
|
82
|
+
value: "N",
|
|
83
|
+
description: "Cap how far back pull requests are read.",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "max-commits",
|
|
87
|
+
value: "N",
|
|
88
|
+
description: "Cap how many commits are read.",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title: "After the plan",
|
|
94
|
+
flags: [
|
|
95
|
+
{
|
|
96
|
+
name: "run",
|
|
97
|
+
description: "Run the recommended init in this same process.",
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
OUTPUT_FLAGS,
|
|
102
|
+
],
|
|
103
|
+
examples: [
|
|
104
|
+
"co-maintainer probe owner/repo",
|
|
105
|
+
"co-maintainer probe owner/repo --run",
|
|
106
|
+
"co-maintainer probe owner/repo --log-time",
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: "init",
|
|
111
|
+
summary: "Build the review guides for a repository for the first time.",
|
|
112
|
+
usage: ["co-maintainer init owner/repo [options]"],
|
|
113
|
+
groups: [
|
|
114
|
+
{
|
|
115
|
+
title: "Sources",
|
|
116
|
+
flags: [
|
|
117
|
+
{ name: "include-codebase", description: "Read the source tree." },
|
|
118
|
+
{
|
|
119
|
+
name: "include-pull-requests",
|
|
120
|
+
description: "Read pull request history.",
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "include-pull-request-changes",
|
|
124
|
+
description: "Read the diffs of those pull requests.",
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "include-commit-history",
|
|
128
|
+
description: "Read commit history.",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "include-how-repo-works",
|
|
132
|
+
description: "Read the docs and layout.",
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
title: "Limits",
|
|
138
|
+
flags: [
|
|
139
|
+
{
|
|
140
|
+
name: "max-commits",
|
|
141
|
+
value: "N",
|
|
142
|
+
default: "all",
|
|
143
|
+
description: "Cap how many commits are read.",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "max-pr-months",
|
|
147
|
+
value: "N",
|
|
148
|
+
default: "all",
|
|
149
|
+
description: "Cap how far back pull requests are read.",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: "max-pull-request-change-lines",
|
|
153
|
+
value: "N",
|
|
154
|
+
default: "all",
|
|
155
|
+
description: "Cap the diff size read.",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "max-comment",
|
|
159
|
+
value: "N",
|
|
160
|
+
description: "Cap the comments read per pull request.",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
title: "Pull request filter",
|
|
166
|
+
flags: [
|
|
167
|
+
{
|
|
168
|
+
name: "pr-state",
|
|
169
|
+
value: "open,closed,merged",
|
|
170
|
+
description: "Which pull request states to read.",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "only-request-changed-pr",
|
|
174
|
+
description: "Read only the pull requests that changed the requested files.",
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
AI_FLAGS,
|
|
179
|
+
GITHUB_FLAGS,
|
|
180
|
+
OUTPUT_FLAGS,
|
|
181
|
+
{
|
|
182
|
+
title: "Performance",
|
|
183
|
+
flags: [
|
|
184
|
+
{
|
|
185
|
+
name: "gh-concurrent",
|
|
186
|
+
value: "N",
|
|
187
|
+
default: "1",
|
|
188
|
+
description: "Concurrent gh calls.",
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: "ai-concurrent",
|
|
192
|
+
value: "N",
|
|
193
|
+
default: "3",
|
|
194
|
+
description: "Concurrent AI calls.",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "improve-matrix",
|
|
198
|
+
value: "N",
|
|
199
|
+
default: "1",
|
|
200
|
+
description: "How many improvement passes to run. Capped at 4, and each pass costs more.",
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
examples: [
|
|
206
|
+
"co-maintainer init owner/repo --include-codebase --include-pull-requests",
|
|
207
|
+
"co-maintainer init owner/repo --include-codebase --ai=openrouter --token=...",
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: "sync",
|
|
212
|
+
// `remake` is the 0.4.13 spelling. It still runs the same handler but is
|
|
213
|
+
// not advertised, so nothing the user reads says "remake" (CORE-21).
|
|
214
|
+
aliases: ["remake"],
|
|
215
|
+
summary: "Rebuild the review guides for a repository that already has them.",
|
|
216
|
+
usage: ["co-maintainer sync owner/repo [options]"],
|
|
217
|
+
groups: [
|
|
218
|
+
{
|
|
219
|
+
title: "Sources",
|
|
220
|
+
flags: [
|
|
221
|
+
{ name: "include-codebase", description: "Read the source tree." },
|
|
222
|
+
{
|
|
223
|
+
name: "include-pull-requests",
|
|
224
|
+
description: "Read pull request history.",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: "include-pull-request-changes",
|
|
228
|
+
description: "Read the diffs of those pull requests.",
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: "include-commit-history",
|
|
232
|
+
description: "Read commit history.",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "include-how-repo-works",
|
|
236
|
+
description: "Read the docs and layout.",
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
title: "Limits",
|
|
242
|
+
flags: [
|
|
243
|
+
{
|
|
244
|
+
name: "max-commits",
|
|
245
|
+
value: "N",
|
|
246
|
+
description: "Cap how many commits are read.",
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: "max-pr-months",
|
|
250
|
+
value: "N",
|
|
251
|
+
description: "Cap how far back pull requests are read.",
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: "max-pull-request-change-lines",
|
|
255
|
+
value: "N",
|
|
256
|
+
description: "Cap the diff size read.",
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: "max-comment",
|
|
260
|
+
value: "N",
|
|
261
|
+
description: "Cap the comments read per pull request.",
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
AI_FLAGS,
|
|
266
|
+
GITHUB_FLAGS,
|
|
267
|
+
OUTPUT_FLAGS,
|
|
268
|
+
],
|
|
269
|
+
examples: ["co-maintainer sync owner/repo --include-codebase"],
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: "review",
|
|
273
|
+
summary: "Review a pull request, or the local changes in this workspace.",
|
|
274
|
+
usage: [
|
|
275
|
+
"co-maintainer review owner/repo PR_NUMBER [options]",
|
|
276
|
+
"co-maintainer review [options]",
|
|
277
|
+
],
|
|
278
|
+
groups: [
|
|
279
|
+
{
|
|
280
|
+
title: "Target",
|
|
281
|
+
flags: [
|
|
282
|
+
{
|
|
283
|
+
name: "repo",
|
|
284
|
+
value: "owner/repo",
|
|
285
|
+
description: "The repository the local changes belong to.",
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: "branch",
|
|
289
|
+
value: "NAME",
|
|
290
|
+
description: "The branch the local changes are on.",
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: "to-branch",
|
|
294
|
+
value: "NAME",
|
|
295
|
+
description: "Compare the local changes against this branch.",
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: "fresh",
|
|
299
|
+
description: "Ignore the previous review and start over.",
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
title: "Local only",
|
|
305
|
+
flags: [
|
|
306
|
+
{
|
|
307
|
+
name: "remote",
|
|
308
|
+
description: "Send the diff to the configured remote server instead of reviewing locally.",
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
name: "remote-host",
|
|
312
|
+
value: "URL",
|
|
313
|
+
description: "Override the configured remote host for this run (needs --remote).",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: "remote-token",
|
|
317
|
+
value: "TOKEN",
|
|
318
|
+
description: "Override the configured remote token for this run (needs --remote).",
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
name: "sync-before-review",
|
|
322
|
+
description: "Rebuild the guides before reviewing.",
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
title: "Codegraph",
|
|
328
|
+
flags: [
|
|
329
|
+
{
|
|
330
|
+
name: "disable-codegraph",
|
|
331
|
+
description: "Skip the codegraph index.",
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
name: "allow-tool-install",
|
|
335
|
+
description: "Install codegraph if it is missing.",
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
},
|
|
339
|
+
AI_FLAGS,
|
|
340
|
+
GITHUB_FLAGS,
|
|
341
|
+
OUTPUT_FLAGS,
|
|
342
|
+
],
|
|
343
|
+
examples: [
|
|
344
|
+
"co-maintainer review owner/repo 42 --json",
|
|
345
|
+
"co-maintainer review --json --disable-codegraph",
|
|
346
|
+
"co-maintainer review --remote --json",
|
|
347
|
+
"co-maintainer review --remote --remote-host=https://review.example.com --remote-token=cmr_...",
|
|
348
|
+
],
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
name: "config",
|
|
352
|
+
summary: "Read and edit the user config without opening the file.",
|
|
353
|
+
usage: [
|
|
354
|
+
"co-maintainer config list",
|
|
355
|
+
"co-maintainer config get <key>",
|
|
356
|
+
"co-maintainer config set <key> <value>",
|
|
357
|
+
"co-maintainer config unset <key>",
|
|
358
|
+
"co-maintainer config path [--all]",
|
|
359
|
+
],
|
|
360
|
+
groups: [
|
|
361
|
+
{
|
|
362
|
+
title: "Subcommands",
|
|
363
|
+
flags: [
|
|
364
|
+
{
|
|
365
|
+
name: "all",
|
|
366
|
+
description: "With `path`, also print the repos and cache directories.",
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
],
|
|
371
|
+
examples: [
|
|
372
|
+
"co-maintainer config list",
|
|
373
|
+
"co-maintainer config get high-model",
|
|
374
|
+
"co-maintainer config set remote-host https://review.example.com",
|
|
375
|
+
"co-maintainer config path --all",
|
|
376
|
+
],
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
name: "view",
|
|
380
|
+
summary: "Print the guides co-maintainer generated for a repository.",
|
|
381
|
+
usage: [
|
|
382
|
+
"co-maintainer view [owner/repo] [guide]",
|
|
383
|
+
"co-maintainer view [owner/repo] --list",
|
|
384
|
+
"co-maintainer view [owner/repo] --path",
|
|
385
|
+
],
|
|
386
|
+
groups: [
|
|
387
|
+
{
|
|
388
|
+
title: "Guides",
|
|
389
|
+
flags: [
|
|
390
|
+
{
|
|
391
|
+
name: "list",
|
|
392
|
+
description: "List the guide files with their size and build date.",
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: "path",
|
|
396
|
+
description: "Print the directory the guides live in.",
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "remote",
|
|
400
|
+
description: "Read the guides from the configured remote review server instead.",
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
examples: [
|
|
406
|
+
"co-maintainer view",
|
|
407
|
+
"co-maintainer view owner/repo review-guide",
|
|
408
|
+
"co-maintainer view owner/repo --list",
|
|
409
|
+
"co-maintainer view owner/repo --remote",
|
|
410
|
+
],
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
name: "set",
|
|
414
|
+
summary: "Persist defaults and secrets to the user config file.",
|
|
415
|
+
usage: ["co-maintainer set [options]"],
|
|
416
|
+
groups: [
|
|
417
|
+
AI_FLAGS,
|
|
418
|
+
GITHUB_FLAGS,
|
|
419
|
+
{
|
|
420
|
+
title: "Server",
|
|
421
|
+
flags: [
|
|
422
|
+
{
|
|
423
|
+
name: "github-app-id",
|
|
424
|
+
value: "ID",
|
|
425
|
+
description: "The GitHub App id.",
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: "github-app-private-key",
|
|
429
|
+
value: "PEM",
|
|
430
|
+
description: "The GitHub App private key.",
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
name: "github-app-private-key-file",
|
|
434
|
+
value: "PATH",
|
|
435
|
+
description: "Read the private key from a file.",
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
name: "github-app-private-key-path",
|
|
439
|
+
value: "PATH",
|
|
440
|
+
description: "Store the key's path only, never its contents.",
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
name: "github-webhook-secret",
|
|
444
|
+
value: "SECRET",
|
|
445
|
+
description: "The webhook HMAC secret.",
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: "github-oauth-client-id",
|
|
449
|
+
value: "ID",
|
|
450
|
+
description: "The GitHub OAuth app client id.",
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
name: "github-oauth-client-secret",
|
|
454
|
+
value: "SECRET",
|
|
455
|
+
description: "The GitHub OAuth app client secret.",
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
name: "github-oauth-allowed-user",
|
|
459
|
+
value: "LOGIN",
|
|
460
|
+
description: "The only GitHub user allowed to sign in.",
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
name: "remote-host",
|
|
464
|
+
value: "URL",
|
|
465
|
+
description: "The remote review server.",
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: "remote-token",
|
|
469
|
+
value: "TOKEN",
|
|
470
|
+
description: "The remote review token.",
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: "review-blocking",
|
|
474
|
+
value: "model|severity",
|
|
475
|
+
default: "model",
|
|
476
|
+
description: "How a review decides a blocking finding.",
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
name: "password",
|
|
480
|
+
value: "TEXT",
|
|
481
|
+
description: "Replace the dashboard password.",
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
name: "disable-auth",
|
|
485
|
+
value: "password",
|
|
486
|
+
description: "Turn the dashboard password off.",
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
name: "enable-auth",
|
|
490
|
+
value: "github",
|
|
491
|
+
description: "Turn GitHub sign-in on.",
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
name: "no-verify",
|
|
495
|
+
description: "Do not check the key and model against OpenRouter.",
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: "unset",
|
|
499
|
+
value: "NAME",
|
|
500
|
+
description: "Remove a stored value.",
|
|
501
|
+
},
|
|
502
|
+
],
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
examples: [
|
|
506
|
+
"co-maintainer set --ai=openrouter --ai-key=... --low-model=... --high-model=...",
|
|
507
|
+
"co-maintainer set --remote-host=https://review.example.com --remote-token=...",
|
|
508
|
+
"co-maintainer set --unset=token",
|
|
509
|
+
],
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
name: "serve",
|
|
513
|
+
summary: "Run the dashboard, the webhook and the job worker.",
|
|
514
|
+
usage: ["co-maintainer serve --port=N [options]"],
|
|
515
|
+
groups: [
|
|
516
|
+
{
|
|
517
|
+
title: "Server",
|
|
518
|
+
flags: [
|
|
519
|
+
{
|
|
520
|
+
name: "port",
|
|
521
|
+
value: "N",
|
|
522
|
+
description: "The port to listen on. Required.",
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
name: "webhook-url",
|
|
526
|
+
value: "URL",
|
|
527
|
+
description: "The public webhook URL. Defaults to localhost.",
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: "password",
|
|
531
|
+
value: "TEXT",
|
|
532
|
+
description: "Set the dashboard password on first start.",
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
name: "disable-auth",
|
|
536
|
+
value: "password",
|
|
537
|
+
description: "Turn the dashboard password off.",
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
name: "enable-auth",
|
|
541
|
+
value: "github",
|
|
542
|
+
description: "Turn GitHub sign-in on.",
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
name: "trust-proxy",
|
|
546
|
+
description: "Trust x-forwarded-for and x-forwarded-proto.",
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
name: "inject-500",
|
|
550
|
+
description: "Return 500 for mutating requests. Debugging only.",
|
|
551
|
+
},
|
|
552
|
+
],
|
|
553
|
+
},
|
|
554
|
+
OUTPUT_FLAGS,
|
|
555
|
+
],
|
|
556
|
+
examples: ["co-maintainer serve --port=5000"],
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
name: "version",
|
|
560
|
+
summary: "Print the version.",
|
|
561
|
+
usage: ["co-maintainer version"],
|
|
562
|
+
groups: [],
|
|
563
|
+
examples: ["co-maintainer version"],
|
|
564
|
+
},
|
|
565
|
+
];
|
|
566
|
+
/** Every name a command answers to, including hidden aliases. */
|
|
567
|
+
export function allNames() {
|
|
568
|
+
const names = [];
|
|
569
|
+
for (const command of COMMANDS) {
|
|
570
|
+
names.push(command.name, ...(command.aliases ?? []));
|
|
571
|
+
}
|
|
572
|
+
return names;
|
|
573
|
+
}
|
|
574
|
+
export function findCommand(name) {
|
|
575
|
+
return COMMANDS.find((command) => command.name === name || command.aliases?.includes(name));
|
|
576
|
+
}
|
|
577
|
+
/** Commands listed in the global help. A hidden alias or command is resolvable
|
|
578
|
+
* but invisible. */
|
|
579
|
+
export function visibleCommands() {
|
|
580
|
+
return COMMANDS.filter((command) => !command.hidden);
|
|
581
|
+
}
|
|
582
|
+
/** Levenshtein distance, iterative and allocation-light: the help path runs it
|
|
583
|
+
* on every unknown token, and the strings are short. */
|
|
584
|
+
export function levenshtein(a, b) {
|
|
585
|
+
if (a === b)
|
|
586
|
+
return 0;
|
|
587
|
+
if (a.length === 0)
|
|
588
|
+
return b.length;
|
|
589
|
+
if (b.length === 0)
|
|
590
|
+
return a.length;
|
|
591
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
592
|
+
for (let i = 1; i <= a.length; i++) {
|
|
593
|
+
const current = [i];
|
|
594
|
+
for (let j = 1; j <= b.length; j++) {
|
|
595
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
596
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + cost);
|
|
597
|
+
}
|
|
598
|
+
previous = current;
|
|
599
|
+
}
|
|
600
|
+
return previous[b.length];
|
|
601
|
+
}
|
|
602
|
+
/** The closest candidate within `maxDistance`, or undefined. Ties keep the
|
|
603
|
+
* first candidate, which is the declaration order in `COMMANDS`. */
|
|
604
|
+
export function closest(input, candidates, maxDistance = 2) {
|
|
605
|
+
let best;
|
|
606
|
+
let bestDistance = maxDistance + 1;
|
|
607
|
+
for (const candidate of candidates) {
|
|
608
|
+
const distance = levenshtein(input.toLowerCase(), candidate.toLowerCase());
|
|
609
|
+
if (distance < bestDistance) {
|
|
610
|
+
bestDistance = distance;
|
|
611
|
+
best = candidate;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return bestDistance <= maxDistance ? best : undefined;
|
|
615
|
+
}
|
|
616
|
+
/** `prob` becomes `Unknown command: prob. Did you mean probe?`. */
|
|
617
|
+
export function unknownCommandMessage(input) {
|
|
618
|
+
const suggestion = closest(input, allNames());
|
|
619
|
+
return suggestion
|
|
620
|
+
? `Unknown command: ${input}. Did you mean ${suggestion}?`
|
|
621
|
+
: `Unknown command: ${input}`;
|
|
622
|
+
}
|
|
623
|
+
/** `--jsno` becomes `Unknown option: --jsno. Did you mean --json?`. */
|
|
624
|
+
export function unknownOptionMessage(input) {
|
|
625
|
+
const flag = input.replace(/^--?/, "").split("=")[0] ?? "";
|
|
626
|
+
const candidates = COMMANDS.flatMap((command) => command.groups.flatMap((group) => group.flags.map((spec) => spec.name)));
|
|
627
|
+
const suggestion = closest(flag, [...new Set(candidates)]);
|
|
628
|
+
return suggestion
|
|
629
|
+
? `Unknown option: ${input}. Did you mean --${suggestion}?`
|
|
630
|
+
: `Unknown option: ${input}`;
|
|
631
|
+
}
|
|
632
|
+
function renderFlags(groups, lines) {
|
|
633
|
+
for (const group of groups) {
|
|
634
|
+
if (group.flags.length === 0)
|
|
635
|
+
continue;
|
|
636
|
+
lines.push("");
|
|
637
|
+
lines.push(`${group.title}:`);
|
|
638
|
+
for (const flag of group.flags) {
|
|
639
|
+
const head = ` --${flag.name}${flag.value ? `=${flag.value}` : ""}`;
|
|
640
|
+
const meta = flag.default !== undefined ? ` (default: ${flag.default})` : "";
|
|
641
|
+
lines.push(`${head.padEnd(42)}${flag.description}${meta}`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
/** The global help: every visible command with its one-line summary. */
|
|
646
|
+
export function renderGlobalHelp() {
|
|
647
|
+
const lines = [];
|
|
648
|
+
lines.push("Usage: co-maintainer <command> owner/repo [options]");
|
|
649
|
+
lines.push("");
|
|
650
|
+
lines.push("Commands:");
|
|
651
|
+
for (const command of visibleCommands()) {
|
|
652
|
+
lines.push(` ${command.name.padEnd(10)}${command.summary}`);
|
|
653
|
+
}
|
|
654
|
+
lines.push("");
|
|
655
|
+
lines.push("Run co-maintainer help <command> for details.");
|
|
656
|
+
return lines.join("\n");
|
|
657
|
+
}
|
|
658
|
+
/** One command's help: usage, flags grouped, examples, docs link. */
|
|
659
|
+
export function renderCommandHelp(name) {
|
|
660
|
+
const command = findCommand(name);
|
|
661
|
+
if (!command)
|
|
662
|
+
return undefined;
|
|
663
|
+
const lines = [];
|
|
664
|
+
lines.push(`co-maintainer ${command.name}: ${command.summary}`);
|
|
665
|
+
lines.push("");
|
|
666
|
+
lines.push("Usage:");
|
|
667
|
+
for (const usage of command.usage)
|
|
668
|
+
lines.push(` ${usage}`);
|
|
669
|
+
renderFlags(command.groups, lines);
|
|
670
|
+
if (command.examples.length > 0) {
|
|
671
|
+
lines.push("");
|
|
672
|
+
lines.push("Examples:");
|
|
673
|
+
for (const example of command.examples)
|
|
674
|
+
lines.push(` ${example}`);
|
|
675
|
+
}
|
|
676
|
+
if (command.docs) {
|
|
677
|
+
lines.push("");
|
|
678
|
+
lines.push(`Docs: ${command.docs}`);
|
|
679
|
+
}
|
|
680
|
+
return lines.join("\n");
|
|
681
|
+
}
|
|
682
|
+
/** The registry as markdown, so CORE-81 can build the command reference from
|
|
683
|
+
* the same data the runtime help uses. */
|
|
684
|
+
export function registryToMarkdown() {
|
|
685
|
+
const lines = [];
|
|
686
|
+
for (const command of visibleCommands()) {
|
|
687
|
+
lines.push(`## \`co-maintainer ${command.name}\``);
|
|
688
|
+
lines.push("");
|
|
689
|
+
lines.push(command.summary);
|
|
690
|
+
lines.push("");
|
|
691
|
+
lines.push("```");
|
|
692
|
+
for (const usage of command.usage)
|
|
693
|
+
lines.push(usage);
|
|
694
|
+
lines.push("```");
|
|
695
|
+
for (const group of command.groups) {
|
|
696
|
+
if (group.flags.length === 0)
|
|
697
|
+
continue;
|
|
698
|
+
lines.push("");
|
|
699
|
+
lines.push(`### ${group.title}`);
|
|
700
|
+
lines.push("");
|
|
701
|
+
lines.push("| Flag | Default | Description |");
|
|
702
|
+
lines.push("|---|---|---|");
|
|
703
|
+
for (const flag of group.flags) {
|
|
704
|
+
const flagCell = flag.value
|
|
705
|
+
? `--${flag.name}=${flag.value}`
|
|
706
|
+
: `--${flag.name}`;
|
|
707
|
+
lines.push(`| \`${flagCell}\` | ${flag.default ?? ""} | ${flag.description} |`);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
lines.push("");
|
|
711
|
+
}
|
|
712
|
+
return lines.join("\n");
|
|
713
|
+
}
|