co-maintainer 0.5.0 → 0.5.1-beta.2

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.
Files changed (177) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +5 -3
  3. package/dist/package.json +1 -1
  4. package/dist/src/ai/anthropic.d.ts +55 -0
  5. package/dist/src/ai/anthropic.js +262 -0
  6. package/dist/src/ai/batch.d.ts +2 -2
  7. package/dist/src/ai/batch.js +1 -1
  8. package/dist/src/ai/estimate.d.ts +4 -0
  9. package/dist/src/ai/estimate.js +17 -2
  10. package/dist/src/ai/mermaid_loop.js +7 -4
  11. package/dist/src/ai/openai.d.ts +45 -0
  12. package/dist/src/ai/openai.js +206 -0
  13. package/dist/src/ai/opencode.d.ts +10 -0
  14. package/dist/src/ai/opencode.js +76 -0
  15. package/dist/src/ai/openrouter.d.ts +23 -7
  16. package/dist/src/ai/openrouter.js +39 -23
  17. package/dist/src/ai/pricing.js +1 -1
  18. package/dist/src/ai/provider.d.ts +9 -0
  19. package/dist/src/ai/provider.js +42 -3
  20. package/dist/src/ai/verify.d.ts +9 -1
  21. package/dist/src/ai/verify.js +81 -3
  22. package/dist/src/cli/args.d.ts +1 -2
  23. package/dist/src/cli/args.js +38 -26
  24. package/dist/src/cli/commands/config.d.ts +1 -1
  25. package/dist/src/cli/commands/config.js +10 -4
  26. package/dist/src/cli/commands/probe.js +3 -11
  27. package/dist/src/cli/commands/registry.d.ts +1 -9
  28. package/dist/src/cli/commands/registry.js +75 -10
  29. package/dist/src/cli/commands/review.js +18 -13
  30. package/dist/src/cli/commands/rollback.d.ts +1 -0
  31. package/dist/src/cli/commands/rollback.js +42 -0
  32. package/dist/src/cli/commands/serve.js +2 -3
  33. package/dist/src/cli/commands/set.js +71 -7
  34. package/dist/src/cli/commands/view.js +10 -9
  35. package/dist/src/cli/error.d.ts +4 -4
  36. package/dist/src/cli/error.js +4 -4
  37. package/dist/src/cli/main.d.ts +4 -4
  38. package/dist/src/cli/main.js +13 -8
  39. package/dist/src/cli/prompt.js +1 -1
  40. package/dist/src/cli/review_args.d.ts +9 -3
  41. package/dist/src/cli/review_args.js +28 -5
  42. package/dist/src/cli/review_github.d.ts +31 -0
  43. package/dist/src/cli/review_github.js +128 -0
  44. package/dist/src/cli/review_result.d.ts +27 -16
  45. package/dist/src/cli/review_result.js +7 -7
  46. package/dist/src/config.d.ts +28 -6
  47. package/dist/src/config.js +15 -1
  48. package/dist/src/git/default_branch.d.ts +1 -1
  49. package/dist/src/git/default_branch.js +1 -1
  50. package/dist/src/github/app.js +2 -2
  51. package/dist/src/github/app_manifest.d.ts +1 -7
  52. package/dist/src/github/app_manifest.js +2 -7
  53. package/dist/src/github/client.d.ts +4 -1
  54. package/dist/src/github/client.js +14 -2
  55. package/dist/src/github/gh.js +10 -7
  56. package/dist/src/github/pat.js +4 -4
  57. package/dist/src/github/permissions.d.ts +36 -0
  58. package/dist/src/github/permissions.js +334 -0
  59. package/dist/src/knowledge/facts.js +1 -1
  60. package/dist/src/knowledge/guide.d.ts +3 -3
  61. package/dist/src/knowledge/guide.js +5 -5
  62. package/dist/src/knowledge/probe.js +1 -2
  63. package/dist/src/knowledge/sections.d.ts +3 -3
  64. package/dist/src/knowledge/sections.js +3 -3
  65. package/dist/src/knowledge/skill.d.ts +1 -1
  66. package/dist/src/knowledge/skill.js +4 -4
  67. package/dist/src/knowledge/synthesis.d.ts +1 -1
  68. package/dist/src/knowledge/synthesis.js +5 -5
  69. package/dist/src/knowledge/types.d.ts +1 -1
  70. package/dist/src/local/codegraph_exclude.d.ts +1 -1
  71. package/dist/src/local/codegraph_exclude.js +1 -1
  72. package/dist/src/local/codegraph_prepare.js +1 -1
  73. package/dist/src/local/git_ops.d.ts +1 -1
  74. package/dist/src/local/git_ops.js +1 -1
  75. package/dist/src/local/git_parse.d.ts +2 -2
  76. package/dist/src/local/git_parse.js +2 -2
  77. package/dist/src/local/git_revision.d.ts +1 -1
  78. package/dist/src/local/git_revision.js +1 -1
  79. package/dist/src/local/git_untracked.d.ts +1 -1
  80. package/dist/src/local/git_untracked.js +1 -1
  81. package/dist/src/local/review_local.js +17 -14
  82. package/dist/src/local/review_lock.d.ts +1 -1
  83. package/dist/src/local/review_lock.js +1 -1
  84. package/dist/src/pr/checkout.js +2 -2
  85. package/dist/src/pr/findings.js +1 -1
  86. package/dist/src/pr/findings_json.d.ts +2 -2
  87. package/dist/src/pr/findings_json.js +1 -1
  88. package/dist/src/pr/github_revision.js +1 -1
  89. package/dist/src/pr/review_copy.d.ts +2 -2
  90. package/dist/src/pr/review_copy.js +2 -2
  91. package/dist/src/pr/reviewer.d.ts +6 -0
  92. package/dist/src/pr/reviewer.js +49 -39
  93. package/dist/src/remote/client.d.ts +4 -0
  94. package/dist/src/remote/client.js +84 -23
  95. package/dist/src/remote/fixtures.js +1 -1
  96. package/dist/src/remote/http.d.ts +10 -1
  97. package/dist/src/remote/http.js +15 -3
  98. package/dist/src/remote/schema.d.ts +3 -3
  99. package/dist/src/remote/schema.js +3 -3
  100. package/dist/src/remote/server/body.d.ts +1 -1
  101. package/dist/src/remote/server/body.js +1 -1
  102. package/dist/src/remote/server/byok_keys.d.ts +15 -0
  103. package/dist/src/remote/server/byok_keys.js +40 -0
  104. package/dist/src/remote/server/guides.js +2 -2
  105. package/dist/src/remote/server/routes.js +8 -1
  106. package/dist/src/remote/validate.js +15 -1
  107. package/dist/src/review/blocking.d.ts +2 -2
  108. package/dist/src/review/blocking.js +2 -2
  109. package/dist/src/review/carry_over.d.ts +2 -2
  110. package/dist/src/review/carry_over.js +2 -2
  111. package/dist/src/review/guides.js +1 -1
  112. package/dist/src/server/api/remote_tokens.js +2 -0
  113. package/dist/src/server/api/repos.js +51 -0
  114. package/dist/src/server/api/settings.js +10 -0
  115. package/dist/src/server/errors.d.ts +1 -1
  116. package/dist/src/server/http.js +1 -1
  117. package/dist/src/server/pages/activity.d.ts +2 -0
  118. package/dist/src/server/pages/activity.js +18 -4
  119. package/dist/src/server/pages/add_repo.js +61 -1
  120. package/dist/src/server/pages/analytics.js +18 -8
  121. package/dist/src/server/pages/cost.d.ts +21 -0
  122. package/dist/src/server/pages/cost.js +72 -0
  123. package/dist/src/server/pages/pr.js +5 -4
  124. package/dist/src/server/pages/repo.js +3 -2
  125. package/dist/src/server/pages/repo_prs.js +3 -2
  126. package/dist/src/server/pages/repo_remote.js +3 -2
  127. package/dist/src/server/pages/repo_settings.js +326 -12
  128. package/dist/src/server/pages/router.js +3 -2
  129. package/dist/src/server/pages/settings.js +50 -6
  130. package/dist/src/server/pages/styles.d.ts +1 -1
  131. package/dist/src/server/pages/styles.js +1 -1
  132. package/dist/src/services/credentials.js +8 -11
  133. package/dist/src/services/dashboard.d.ts +22 -9
  134. package/dist/src/services/dashboard.js +16 -2
  135. package/dist/src/services/probe.js +1 -1
  136. package/dist/src/services/remote_review.js +142 -35
  137. package/dist/src/services/remote_review_abort.d.ts +5 -1
  138. package/dist/src/services/remote_review_abort.js +9 -1
  139. package/dist/src/services/review.d.ts +1 -1
  140. package/dist/src/services/review.js +19 -5
  141. package/dist/src/services/review_policy.d.ts +116 -0
  142. package/dist/src/services/review_policy.js +489 -0
  143. package/dist/src/services/setup.d.ts +4 -3
  144. package/dist/src/services/setup.js +18 -16
  145. package/dist/src/services/setup_checklist.js +2 -2
  146. package/dist/src/services/webhook.d.ts +23 -0
  147. package/dist/src/services/webhook.js +141 -34
  148. package/dist/src/store/app_db.d.ts +5 -0
  149. package/dist/src/store/app_db.js +69 -13
  150. package/dist/src/store/backup.d.ts +31 -0
  151. package/dist/src/store/backup.js +158 -0
  152. package/dist/src/store/migrations.d.ts +1 -1
  153. package/dist/src/store/migrations.js +21 -1
  154. package/dist/src/store/remote_review_inputs.d.ts +3 -0
  155. package/dist/src/store/remote_review_inputs.js +3 -3
  156. package/dist/src/store/remote_tokens.d.ts +1 -1
  157. package/dist/src/store/remote_tokens.js +1 -1
  158. package/dist/src/store/repos.d.ts +2 -2
  159. package/dist/src/store/repos.js +1 -1
  160. package/dist/src/store/reviews.d.ts +21 -13
  161. package/dist/src/store/reviews.js +60 -15
  162. package/dist/src/store/rows.d.ts +10 -0
  163. package/dist/src/tools/codegraph.d.ts +4 -4
  164. package/dist/src/tools/codegraph.js +5 -5
  165. package/dist/src/tools/codegraph_exec.d.ts +1 -1
  166. package/dist/src/tools/codegraph_exec.js +1 -1
  167. package/dist/src/types.d.ts +12 -6
  168. package/dist/src/util/cost.d.ts +52 -0
  169. package/dist/src/util/cost.js +70 -0
  170. package/dist/src/util/log.d.ts +1 -1
  171. package/dist/src/util/log.js +2 -2
  172. package/dist/src/util/redact.js +2 -0
  173. package/dist/src/util/run_summary.d.ts +7 -2
  174. package/dist/src/util/run_summary.js +28 -2
  175. package/dist/src/util/time.d.ts +1 -1
  176. package/dist/src/util/time.js +1 -1
  177. package/package.json +1 -1
@@ -0,0 +1,334 @@
1
+ /** The one list of GitHub calls this codebase makes and what each needs.
2
+ *
3
+ * The App manifest, the App permission check on save, the 403 and 404 hints
4
+ * and the permission tables in the docs are all read from `ENDPOINTS`.
5
+ * `permissions.test.ts` scans the source for every endpoint it calls and fails
6
+ * when one is missing here, so a new call cannot ship without its permission. */
7
+ /** Key order is the order the manifest and the doc tables list them in. */
8
+ export const PERMISSION_LABEL = {
9
+ contents: "Contents",
10
+ issues: "Issues",
11
+ pull_requests: "Pull requests",
12
+ checks: "Checks",
13
+ metadata: "Metadata",
14
+ };
15
+ const ORDER = Object.keys(PERMISSION_LABEL);
16
+ const READERS = ["gh", "pat", "app"];
17
+ const APP_ONLY = ["app"];
18
+ export const ENDPOINTS = [
19
+ {
20
+ method: "GET",
21
+ pattern: "repos/{repo}",
22
+ permission: "metadata",
23
+ level: "read",
24
+ identities: READERS,
25
+ feature: "Read the repository and its default branch",
26
+ },
27
+ {
28
+ method: "GET",
29
+ pattern: "repos/{repo}/pulls",
30
+ permission: "pull_requests",
31
+ level: "read",
32
+ identities: READERS,
33
+ feature: "List pull requests",
34
+ },
35
+ {
36
+ method: "GET",
37
+ pattern: "repos/{repo}/pulls/{n}",
38
+ permission: "pull_requests",
39
+ level: "read",
40
+ identities: READERS,
41
+ feature: "Read a pull request",
42
+ },
43
+ {
44
+ method: "GET",
45
+ pattern: "repos/{repo}/pulls/{n}/files",
46
+ permission: "pull_requests",
47
+ level: "read",
48
+ identities: READERS,
49
+ feature: "Read the files a pull request changes",
50
+ },
51
+ {
52
+ method: "GET",
53
+ pattern: "repos/{repo}/pulls/{n}/reviews",
54
+ permission: "pull_requests",
55
+ level: "read",
56
+ identities: READERS,
57
+ feature: "Read earlier reviews",
58
+ },
59
+ {
60
+ method: "GET",
61
+ pattern: "repos/{repo}/pulls/{n}/comments",
62
+ permission: "pull_requests",
63
+ level: "read",
64
+ identities: READERS,
65
+ feature: "Read review comment threads",
66
+ },
67
+ {
68
+ method: "POST",
69
+ pattern: "repos/{repo}/pulls/{n}/reviews",
70
+ permission: "pull_requests",
71
+ level: "write",
72
+ identities: APP_ONLY,
73
+ feature: "Post a review",
74
+ },
75
+ {
76
+ method: "POST",
77
+ pattern: "repos/{repo}/pulls/{n}/comments",
78
+ permission: "pull_requests",
79
+ level: "write",
80
+ identities: APP_ONLY,
81
+ feature: "Reply in a review comment thread",
82
+ },
83
+ {
84
+ method: "GET",
85
+ pattern: "repos/{repo}/issues/{n}/comments",
86
+ permission: "issues",
87
+ level: "read",
88
+ identities: READERS,
89
+ feature: "Read the conversation on a pull request",
90
+ },
91
+ {
92
+ method: "POST",
93
+ pattern: "repos/{repo}/issues/{n}/comments",
94
+ permission: "issues",
95
+ level: "write",
96
+ identities: APP_ONLY,
97
+ feature: "Post a conversation comment",
98
+ },
99
+ {
100
+ method: "POST",
101
+ pattern: "repos/{repo}/issues/{n}/reactions",
102
+ permission: "issues",
103
+ level: "write",
104
+ identities: APP_ONLY,
105
+ feature: "Acknowledge a review request on the pull request",
106
+ },
107
+ {
108
+ method: "POST",
109
+ pattern: "repos/{repo}/issues/comments/{id}/reactions",
110
+ permission: "issues",
111
+ level: "write",
112
+ identities: APP_ONLY,
113
+ feature: "Acknowledge a review request in a comment",
114
+ },
115
+ {
116
+ method: "GET",
117
+ pattern: "repos/{repo}/contents/{path}",
118
+ permission: "contents",
119
+ level: "read",
120
+ identities: READERS,
121
+ feature: "Read files and PR_REVIEW_GUIDE.md",
122
+ },
123
+ {
124
+ method: "GET",
125
+ pattern: "repos/{repo}/git/trees/{ref}",
126
+ permission: "contents",
127
+ level: "read",
128
+ identities: READERS,
129
+ feature: "Read the file tree",
130
+ },
131
+ {
132
+ method: "GET",
133
+ pattern: "repos/{repo}/commits",
134
+ permission: "contents",
135
+ level: "read",
136
+ identities: READERS,
137
+ feature: "Read commit history",
138
+ },
139
+ {
140
+ method: "GET",
141
+ pattern: "repos/{repo}/compare/{range}",
142
+ permission: "contents",
143
+ level: "read",
144
+ identities: READERS,
145
+ feature: "Compare two commits",
146
+ },
147
+ {
148
+ method: "GET",
149
+ pattern: "repos/{repo}/releases",
150
+ permission: "contents",
151
+ level: "read",
152
+ identities: READERS,
153
+ feature: "Read releases in the probe",
154
+ },
155
+ {
156
+ method: "POST",
157
+ pattern: "repos/{repo}/check-runs",
158
+ permission: "checks",
159
+ level: "write",
160
+ identities: APP_ONLY,
161
+ feature: "Create the review check run",
162
+ },
163
+ {
164
+ method: "PATCH",
165
+ pattern: "repos/{repo}/check-runs/{id}",
166
+ permission: "checks",
167
+ level: "write",
168
+ identities: APP_ONLY,
169
+ feature: "Update the review check run",
170
+ },
171
+ // Calls that need no repository permission. `credentials.ts` and `gh.ts`
172
+ // make the first two, `app.ts` the App ones, `oauth.ts` the dashboard sign-in.
173
+ {
174
+ method: "GET",
175
+ pattern: "user",
176
+ identities: ["gh", "pat"],
177
+ feature: "Check who the credential belongs to",
178
+ },
179
+ {
180
+ method: "GET",
181
+ pattern: "user/repos",
182
+ permission: "metadata",
183
+ level: "read",
184
+ identities: ["pat"],
185
+ feature: "Check the token can list repositories",
186
+ },
187
+ {
188
+ method: "GET",
189
+ pattern: "rate_limit",
190
+ identities: ["gh"],
191
+ feature: "Print the remaining quota with --debug",
192
+ },
193
+ {
194
+ method: "GET",
195
+ pattern: "app/installations",
196
+ identities: APP_ONLY,
197
+ feature: "List where the App is installed",
198
+ },
199
+ {
200
+ method: "POST",
201
+ pattern: "app/installations/{id}/access_tokens",
202
+ identities: APP_ONLY,
203
+ feature: "Mint an installation token",
204
+ },
205
+ {
206
+ method: "GET",
207
+ pattern: "installation/repositories",
208
+ identities: APP_ONLY,
209
+ feature: "List the repositories an installation can see",
210
+ },
211
+ {
212
+ method: "POST",
213
+ pattern: "app-manifests/{code}/conversions",
214
+ identities: [],
215
+ feature: "Finish creating the App from the dashboard",
216
+ },
217
+ ];
218
+ function strongest(identity) {
219
+ const result = {};
220
+ for (const endpoint of ENDPOINTS) {
221
+ if (!endpoint.permission || !endpoint.identities.includes(identity)) {
222
+ continue;
223
+ }
224
+ const entry = (result[endpoint.permission] ??= {
225
+ level: "read",
226
+ features: [],
227
+ });
228
+ if (endpoint.level === "write")
229
+ entry.level = "write";
230
+ entry.features.push(endpoint.feature);
231
+ }
232
+ return result;
233
+ }
234
+ /** What the App must be granted, in the shape the manifest and the save-time
235
+ * check want. */
236
+ export const APP_PERMISSIONS = Object.fromEntries(ORDER.flatMap((name) => {
237
+ const entry = strongest("app")[name];
238
+ return entry ? [[name, entry.level]] : [];
239
+ }));
240
+ function patternRegex(pattern) {
241
+ const source = pattern
242
+ .split(/(\{[a-z]+\})/)
243
+ .map((part) => {
244
+ if (part === "{repo}")
245
+ return "[^/]+/[^/]+";
246
+ if (part === "{path}")
247
+ return ".+";
248
+ if (part.startsWith("{"))
249
+ return "[^/]+";
250
+ return part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
251
+ })
252
+ .join("");
253
+ return new RegExp(`^${source}$`);
254
+ }
255
+ const REGEXES = ENDPOINTS.map((endpoint) => patternRegex(endpoint.pattern));
256
+ /** The entry for a real request such as `repos/o/r/pulls/4/files?page=2`. */
257
+ export function endpointFor(method, endpoint) {
258
+ const path = endpoint.replace(/\?.*$/, "").replace(/^\/+/, "");
259
+ const index = ENDPOINTS.findIndex((candidate, at) => candidate.method === method && REGEXES[at].test(path));
260
+ return index === -1 ? undefined : ENDPOINTS[index];
261
+ }
262
+ function accessLabel(level) {
263
+ return level === "write" ? "Read and write" : "Read";
264
+ }
265
+ /** `who` is what the failing credential is called in the sentence. */
266
+ export function refusalHint(method, endpoint, who) {
267
+ const base = `GitHub refused ${method} ${endpoint}.`;
268
+ const found = endpointFor(method, endpoint);
269
+ if (!found?.permission)
270
+ return base;
271
+ if (who === "token" && !found.identities.includes("pat")) {
272
+ return `${base} Only a GitHub App can do this.`;
273
+ }
274
+ return `${base} ${needs(found, who)}`;
275
+ }
276
+ /** A fine-grained token is granted permissions and a classic one scopes, so a
277
+ * token error names both. */
278
+ function needs(found, who) {
279
+ const grant = `${PERMISSION_LABEL[found.permission]}: ${accessLabel(found.level)}`;
280
+ return who === "App"
281
+ ? `The GitHub App needs ${grant}.`
282
+ : `A fine-grained token needs ${grant}. A classic token needs the repo scope.`;
283
+ }
284
+ export function missingHint(method, endpoint, who) {
285
+ const name = who === "token" ? "the token" : "the GitHub App";
286
+ const found = endpointFor(method, endpoint);
287
+ const base = `GitHub returned 404 for ${method} ${endpoint}. The repository may not exist or ${name} cannot see it.`;
288
+ if (!found?.permission)
289
+ return base;
290
+ return `${base} ${needs(found, who)}`;
291
+ }
292
+ /** Classic scopes cover every repository call above, for `gh` and a classic
293
+ * PAT alike. No scope is finer than that. */
294
+ const SCOPES = [
295
+ { scope: "repo", why: "Read public and private repositories" },
296
+ { scope: "public_repo", why: "Read public repositories only" },
297
+ ];
298
+ function rows(header, body) {
299
+ const line = (cells) => `| ${cells.join(" | ")} |`;
300
+ return [
301
+ line(header),
302
+ line(header.map((cell) => "-".repeat(Math.max(3, cell.length)))),
303
+ ...body.map(line),
304
+ ].join("\n");
305
+ }
306
+ function byPermission(identity, why) {
307
+ const strong = strongest(identity);
308
+ return rows(identity === "app"
309
+ ? ["Permission", "Access", why]
310
+ : ["Repository permission", "Access", why], ORDER.filter((name) => strong[name]).map((name) => [
311
+ PERMISSION_LABEL[name],
312
+ accessLabel(strong[name].level),
313
+ [...new Set(strong[name].features)]
314
+ .map((text, at) => at === 0 ? text : text[0].toLowerCase() + text.slice(1))
315
+ .join(", "),
316
+ ]));
317
+ }
318
+ /** A markdown table for the docs. `build_docs.ts` writes it between the
319
+ * `permissions:<kind>` markers and a test fails when the page is stale. */
320
+ export function permissionTable(kind) {
321
+ if (kind === "app")
322
+ return byPermission("app", "Why");
323
+ if (kind === "pat-fine")
324
+ return byPermission("pat", "Needed for");
325
+ if (kind === "oauth") {
326
+ return rows(["Scope", "Why"], [
327
+ [
328
+ "None requested",
329
+ "The sign-in only reads your GitHub login from `GET /user`",
330
+ ],
331
+ ]);
332
+ }
333
+ return rows(["Scope", "Why"], SCOPES.map(({ scope, why }) => [`\`${scope}\``, why]));
334
+ }
@@ -295,7 +295,7 @@ export function extractFacts(source, options) {
295
295
  add(facts, {
296
296
  ...fact("review-bar", instruction, `review discussion (${count} mentions)`, count),
297
297
  // A rule mined from discussion across several pull requests is
298
- // repository policy, not one request's narrative (CORE-32).
298
+ // repository policy, not one request's narrative.
299
299
  origin: "repository",
300
300
  });
301
301
  }
@@ -5,10 +5,10 @@ export type ReviewDocuments = {
5
5
  };
6
6
  /** A fact read out of a single pull request describes that request, not the
7
7
  * repository. `origin` is absent on facts written before the field existed, so
8
- * those count as repository policy (CORE-32 / F26b). */
8
+ * those count as repository policy. */
9
9
  export declare function isPullRequestFact(item: Fact): boolean;
10
10
  /** The selected review signals, before the `>2` threshold is applied. Exported
11
- * so `init` can tell the user how far short of the threshold a repository is
12
- * (CORE-31), rather than silently skipping the two guide files. */
11
+ * so `init` can tell the user how far short of the threshold a repository is,
12
+ * rather than silently skipping the two guide files. */
13
13
  export declare function reviewSignalCount(facts: Fact[]): number;
14
14
  export declare function buildReviewDocuments(facts: Fact[]): ReviewDocuments | undefined;
@@ -1,6 +1,6 @@
1
1
  /** A fact read out of a single pull request describes that request, not the
2
2
  * repository. `origin` is absent on facts written before the field existed, so
3
- * those count as repository policy (CORE-32 / F26b). */
3
+ * those count as repository policy. */
4
4
  export function isPullRequestFact(item) {
5
5
  return item.origin === "pull-request";
6
6
  }
@@ -22,12 +22,12 @@ function reviewBarFacts(facts) {
22
22
  .sort((a, b) => b.weight - a.weight || a.claim.localeCompare(b.claim));
23
23
  }
24
24
  /** The short guide's checklist: every recurring review signal, including the
25
- * ones mined from pull requests (CORE-32 keeps this file's PR source). */
25
+ * ones mined from pull requests. */
26
26
  function reviewFacts(facts) {
27
27
  return dedupe(reviewBarFacts(facts));
28
28
  }
29
29
  /** The detailed guide's checklist: only expectations backed by repository-wide
30
- * evidence, never a single pull request's narrative (CORE-32). */
30
+ * evidence, never a single pull request's narrative. */
31
31
  function detailedFacts(facts) {
32
32
  return dedupe(reviewBarFacts(facts).filter((item) => !isPullRequestFact(item)));
33
33
  }
@@ -65,8 +65,8 @@ ${bullets.join("\n")}
65
65
  `;
66
66
  }
67
67
  /** The selected review signals, before the `>2` threshold is applied. Exported
68
- * so `init` can tell the user how far short of the threshold a repository is
69
- * (CORE-31), rather than silently skipping the two guide files. */
68
+ * so `init` can tell the user how far short of the threshold a repository is,
69
+ * rather than silently skipping the two guide files. */
70
70
  export function reviewSignalCount(facts) {
71
71
  return reviewFacts(facts).length;
72
72
  }
@@ -114,8 +114,7 @@ export function analyzeProbe(meta, pulls, detailSamples, commits) {
114
114
  else if (commits.length) {
115
115
  // Only claim the history is noise when the useful-commit ratio actually
116
116
  // supports it. With `commits: 8 · useful: 5` the ratio is above a half,
117
- // and the old unconditional sentence contradicted the numbers beside it
118
- // (CORE-24).
117
+ // and the old unconditional sentence contradicted the numbers beside it.
119
118
  const usefulRatio = usefulCommits / commits.length;
120
119
  if (usefulRatio < 0.5) {
121
120
  reasons.push("Commit history is mostly merge/noise commits, so it is not recommended as a source.");
@@ -1,11 +1,11 @@
1
1
  export declare const sectionTitles: Record<string, string>;
2
2
  export declare const sectionKeys: string[];
3
3
  /** Sections whose content also lives in `CODEBASE.md`. The skill links to that
4
- * file instead of keeping a second copy (CORE-32 / F26c). */
4
+ * file instead of keeping a second copy. */
5
5
  export declare const codebaseSectionKeys: Set<string>;
6
6
  /** A fact read out of a single pull request describes that request, not the
7
7
  * repository, so it may only feed the `review-bar` checklist. Every other
8
- * section states repository policy and must not learn from one PR's narrative
9
- * (CORE-32 / F26b). Keep this in sync with `guide.ts`, which applies the same
8
+ * section states repository policy and must not learn from one PR's narrative.
9
+ * Keep this in sync with `guide.ts`, which applies the same
10
10
  * rule to the review guides. */
11
11
  export declare function sectionAllowsPrFacts(key: string): boolean;
@@ -12,7 +12,7 @@ export const sectionTitles = {
12
12
  };
13
13
  export const sectionKeys = Object.keys(sectionTitles);
14
14
  /** Sections whose content also lives in `CODEBASE.md`. The skill links to that
15
- * file instead of keeping a second copy (CORE-32 / F26c). */
15
+ * file instead of keeping a second copy. */
16
16
  export const codebaseSectionKeys = new Set([
17
17
  "layout",
18
18
  "style",
@@ -21,8 +21,8 @@ export const codebaseSectionKeys = new Set([
21
21
  ]);
22
22
  /** A fact read out of a single pull request describes that request, not the
23
23
  * repository, so it may only feed the `review-bar` checklist. Every other
24
- * section states repository policy and must not learn from one PR's narrative
25
- * (CORE-32 / F26b). Keep this in sync with `guide.ts`, which applies the same
24
+ * section states repository policy and must not learn from one PR's narrative.
25
+ * Keep this in sync with `guide.ts`, which applies the same
26
26
  * rule to the review guides. */
27
27
  export function sectionAllowsPrFacts(key) {
28
28
  return key === "review-bar";
@@ -2,7 +2,7 @@ import type { Fact } from "./types.ts";
2
2
  /** The full text of the sections that live in `CODEBASE.md`. The skill itself
3
3
  * only links to that file, so this is the single place the codebase guidance is
4
4
  * written out: the synthesized override when there is one, otherwise the
5
- * rendered facts (CORE-32 / F26c). */
5
+ * rendered facts. */
6
6
  export declare function codebaseBody(facts: Fact[], overrides?: Record<string, string>): string;
7
7
  /** Slices an assembled skill's `## Heading` sections back out by section key,
8
8
  * from `<!-- section:key -->` markers or (fallback) canonical heading text. */
@@ -6,8 +6,8 @@ function sectionFacts(facts, key) {
6
6
  .sort((a, b) => b.weight - a.weight);
7
7
  }
8
8
  /** Facts a section may state. A fact read out of a single pull request is that
9
- * request's narrative, not a rule, so only `review-bar` may use it (CORE-32 /
10
- * F26b). Facts written before `origin` existed count as repository policy. */
9
+ * request's narrative, not a rule, so only `review-bar` may use it. Facts
10
+ * written before `origin` existed count as repository policy. */
11
11
  function usableFacts(facts, key) {
12
12
  const items = sectionFacts(facts, key);
13
13
  return sectionAllowsPrFacts(key)
@@ -42,7 +42,7 @@ function codebaseSectionText(key, facts, overrides) {
42
42
  /** The full text of the sections that live in `CODEBASE.md`. The skill itself
43
43
  * only links to that file, so this is the single place the codebase guidance is
44
44
  * written out: the synthesized override when there is one, otherwise the
45
- * rendered facts (CORE-32 / F26c). */
45
+ * rendered facts. */
46
46
  export function codebaseBody(facts, overrides = {}) {
47
47
  return [...codebaseSectionKeys]
48
48
  .map((key) => codebaseSectionText(key, facts, overrides))
@@ -83,7 +83,7 @@ async function hash(value) {
83
83
  }
84
84
  /** The fields that decide a section's text. `origin` is included so a fact
85
85
  * moving from PR narrative to repository policy (or the reverse) counts as a
86
- * change rather than reusing a section built under the old rule (CORE-32). */
86
+ * change rather than reusing a section built under the old rule. */
87
87
  function hashInput(item) {
88
88
  return [
89
89
  item.id,
@@ -10,7 +10,7 @@ export declare function extractAiFactsWithReport(provider: AiProvider, repo: str
10
10
  skipped: SkippedUnit[];
11
11
  }>;
12
12
  /** Same as {@link extractAiFacts}, but also reports what the batch skipped so
13
- * the caller can put it in the final `[done]` line (CORE-30). */
13
+ * the caller can put it in the final `[done]` line. */
14
14
  export declare function enrichFactsWithReport(provider: AiProvider, repo: string, base: Fact[], source: Source, options: Options, usage?: UsageSink): Promise<{
15
15
  facts: Fact[];
16
16
  skipped: SkippedUnit[];
@@ -131,7 +131,7 @@ function queueFor(provider, repo, ai, model, concurrency, validate) {
131
131
  }
132
132
  /** `factsFromResponse` as a validator: `null` when the text parses into facts,
133
133
  * otherwise the parse error's message. Used so an unparseable response is never
134
- * cached (CORE-30). */
134
+ * cached. */
135
135
  function validateFacts(response, evidence, defaultScope) {
136
136
  try {
137
137
  factsFromResponse(response.text, evidence, defaultScope, "repository");
@@ -187,7 +187,7 @@ function sectionGoal(key) {
187
187
  function synthesisFacts(facts, key) {
188
188
  return (facts
189
189
  // A section that states repository policy never learns from a single pull
190
- // request's narrative; only `review-bar` may (CORE-32 / F26b).
190
+ // request's narrative; only `review-bar` may.
191
191
  .filter((item) => item.sectionKey === key &&
192
192
  (sectionAllowsPrFacts(key) || !isPullRequestFact(item)))
193
193
  .sort((a, b) => (b.status === "active" ? 1 : 0) - (a.status === "active" ? 1 : 0) ||
@@ -283,7 +283,7 @@ ${files}`, 2_200));
283
283
  return { facts, skipped: queue.skippedUnits() };
284
284
  }
285
285
  /** Same as {@link extractAiFacts}, but also reports what the batch skipped so
286
- * the caller can put it in the final `[done]` line (CORE-30). */
286
+ * the caller can put it in the final `[done]` line. */
287
287
  export async function enrichFactsWithReport(provider, repo, base, source, options, usage) {
288
288
  const { facts, skipped } = await extractAiFactsWithReport(provider, repo, source, options, usage);
289
289
  return { facts: mergeFacts(base, facts), skipped };
@@ -315,7 +315,7 @@ export async function synthesizeSections(provider, repo, facts, _previousMarkdow
315
315
  const relevant = synthesisFacts(facts, key);
316
316
  // A section whose only facts came from a single pull request has no
317
317
  // repository policy to synthesize, so it is left to the deterministic
318
- // renderer instead of asking the model for an empty answer (CORE-32).
318
+ // renderer instead of asking the model for an empty answer.
319
319
  if (!relevant.length)
320
320
  continue;
321
321
  keys.push(key);
@@ -354,7 +354,7 @@ FACTS:
354
354
  ${JSON.stringify(relevant)}`,
355
355
  });
356
356
  }
357
- const queue = queueFor(provider, repo, ai, model, ai === "hetzner" ? 1 : concurrency, (request, response) => validateSection(response, keys[requests.indexOf(request)] ?? ""));
357
+ const queue = queueFor(provider, repo, ai, model, concurrency, (request, response) => validateSection(response, keys[requests.indexOf(request)] ?? ""));
358
358
  const responses = await queue.run(requests, usage);
359
359
  // A section that the batch skipped has no response, and a unit that failed
360
360
  // validation never produces one: omit those keys entirely rather than
@@ -41,7 +41,7 @@ export type Fact = {
41
41
  status: "active" | "contradicted" | "stale";
42
42
  /** Where the fact was mined from. A fact read out of a single pull request
43
43
  * describes that request, not the repository, so it may not become a
44
- * repository-wide rule (CORE-32 / F26b). Missing means `repository`, which
44
+ * repository-wide rule. Missing means `repository`, which
45
45
  * keeps facts written before this field existed. */
46
46
  origin?: "repository" | "pull-request";
47
47
  };
@@ -1,3 +1,3 @@
1
1
  import type { Run } from "../pr/checkout.ts";
2
- /** Plan §13.2 — hide the local codegraph index from git status. */
2
+ /** Hide the local codegraph index from git status. */
3
3
  export declare function ensureCodegraphGitExclude(gitRoot: string, run: Run): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import { dirname } from "node:path";
2
2
  import { isNotFound, mkdir, readTextFile, writeTextFile, } from "../util/runtime.js";
3
3
  const EXCLUDE_LINE = "/.co-maintainer-codegraph/";
4
- /** Plan §13.2 — hide the local codegraph index from git status. */
4
+ /** Hide the local codegraph index from git status. */
5
5
  export async function ensureCodegraphGitExclude(gitRoot, run) {
6
6
  const pathResult = await run("git", ["rev-parse", "--git-path", "info/exclude"], gitRoot);
7
7
  if (pathResult.code !== 0)
@@ -13,7 +13,7 @@ export async function prepareLocalCodegraph(input) {
13
13
  const resolved = await ensureCodegraphForReview({
14
14
  allowInstall: input.allowInstall,
15
15
  // The prompt is safe only when a human can answer it; `canPrompt` checks
16
- // stdin, stdout and `CI`, so a `</dev/null` or piped run never asks (F01).
16
+ // stdin, stdout and `CI`, so a `</dev/null` or piped run never asks.
17
17
  interactive: input.interactive ?? canPrompt(),
18
18
  log: (message) => log("codegraph", message.replace(/^\[codegraph\]\s*/, "")),
19
19
  });
@@ -2,7 +2,7 @@ import { type Run } from "../pr/checkout.ts";
2
2
  import { CliError } from "../cli/error.ts";
3
3
  export declare function gitRoot(cwd: string, run?: Run): Promise<string>;
4
4
  /** Backward-compatible name for the shared CLI error. Local and remote review
5
- * threw this before CORE-10 introduced `CliError`, so it stays as a thin
5
+ * threw this before `CliError` existed, so it stays as a thin
6
6
  * subclass and every existing call site keeps working. */
7
7
  export declare class ReviewCliError extends CliError {
8
8
  constructor(code: string, message: string, hint?: string, exitCode?: number);
@@ -10,7 +10,7 @@ export async function gitRoot(cwd, run = runCommand) {
10
10
  return result.stdout.trim();
11
11
  }
12
12
  /** Backward-compatible name for the shared CLI error. Local and remote review
13
- * threw this before CORE-10 introduced `CliError`, so it stays as a thin
13
+ * threw this before `CliError` existed, so it stays as a thin
14
14
  * subclass and every existing call site keeps working. */
15
15
  export class ReviewCliError extends CliError {
16
16
  constructor(code, message, hint, exitCode = EXIT_USAGE) {
@@ -1,4 +1,4 @@
1
- /** Pure parsers for git -z output and remote URL normalization (plan §10). */
1
+ /** Pure parsers for git -z output and remote URL normalization. */
2
2
  export type NameStatusEntry = {
3
3
  status: "added" | "modified" | "removed" | "renamed";
4
4
  path: string;
@@ -21,7 +21,7 @@ export declare function normalizeGithubRemote(url: string): NormalizeRemoteResul
21
21
  export declare function parseNameStatusZ(raw: string): NameStatusEntry[];
22
22
  /** Parse `git diff --numstat -z` (`add\tdelete\tpath\0` per file). */
23
23
  export declare function parseNumstatZ(raw: string): Map<string, NumstatEntry>;
24
- /** Paths from name-status that have no entry in a bulk unified diff (plan §10.7). */
24
+ /** Paths from name-status that have no entry in a bulk unified diff. */
25
25
  export declare function pathsMissingPatches(statuses: NameStatusEntry[], patches: Map<string, string>): string[];
26
26
  /** Split unified diff output into per-file patch bodies (without diff --git header). */
27
27
  export declare function splitDiffPatches(raw: string): Map<string, string>;
@@ -1,4 +1,4 @@
1
- /** Pure parsers for git -z output and remote URL normalization (plan §10). */
1
+ /** Pure parsers for git -z output and remote URL normalization. */
2
2
  export function normalizeGithubRemote(url) {
3
3
  const trimmed = url.trim().replace(/\/+$/, "");
4
4
  let host = "";
@@ -102,7 +102,7 @@ export function parseNumstatZ(raw) {
102
102
  }
103
103
  return map;
104
104
  }
105
- /** Paths from name-status that have no entry in a bulk unified diff (plan §10.7). */
105
+ /** Paths from name-status that have no entry in a bulk unified diff. */
106
106
  export function pathsMissingPatches(statuses, patches) {
107
107
  return statuses
108
108
  .filter((entry) => entry.status !== "removed")
@@ -1,7 +1,7 @@
1
1
  import type { Run } from "../pr/checkout.ts";
2
2
  import { type Revision } from "../review/revision.ts";
3
3
  import { type UntrackedWarning } from "./git_untracked.ts";
4
- /** Single-file unified patch when bulk `git diff` did not map a path (plan §10.7). */
4
+ /** Single-file unified patch when bulk `git diff` did not map a path. */
5
5
  export declare function perFileUnifiedPatch(cwd: string, base: string, path: string, run: Run): Promise<string>;
6
6
  export declare function mergeBase(cwd: string, baseRef: string, remote: string, run: Run): Promise<string>;
7
7
  export declare function resolveBaseRef(cwd: string, remote: string, toBranch: string | undefined, run: Run): Promise<{
@@ -12,7 +12,7 @@ const unifiedDiffArgs = [
12
12
  "-M",
13
13
  "--unified=3",
14
14
  ];
15
- /** Single-file unified patch when bulk `git diff` did not map a path (plan §10.7). */
15
+ /** Single-file unified patch when bulk `git diff` did not map a path. */
16
16
  export async function perFileUnifiedPatch(cwd, base, path, run) {
17
17
  const result = await run("git", [...diffEnv, ...unifiedDiffArgs, base, "--", path], cwd);
18
18
  if (result.code !== 0 || !result.stdout.trim())
@@ -3,7 +3,7 @@ export type UntrackedWarning = {
3
3
  code: "untracked_unreadable";
4
4
  message: string;
5
5
  };
6
- /** Build patch for a new untracked file (plan §10.8). */
6
+ /** Build patch for a new untracked file. */
7
7
  export declare function patchFromNewFileContent(content: Uint8Array): {
8
8
  patch: string;
9
9
  additions: number;