@humanbased/crosscheck 1.2.0 → 1.3.0-beta.81

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 (314) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +182 -375
  3. package/README.zh.md +1 -1
  4. package/assets/icon-256.png +0 -0
  5. package/assets/linear-comment.svg +18 -0
  6. package/assets/linear-onboard.svg +30 -0
  7. package/assets/linear-status.svg +23 -0
  8. package/assets/linear-test.svg +34 -0
  9. package/assets/skills/code-review/.crosscheck-skill.json +9 -0
  10. package/assets/skills/code-review/LICENSE +21 -0
  11. package/assets/skills/code-review/SKILL.md +89 -0
  12. package/assets/skills/code-review/agents/openai.yaml +3 -0
  13. package/assets/skills/code-review-skill/.crosscheck-skill.json +9 -0
  14. package/assets/skills/code-review-skill/LICENSE +21 -0
  15. package/assets/skills/code-review-skill/SKILL.md +231 -0
  16. package/assets/skills/code-review-skill/assets/pr-review-template.md +137 -0
  17. package/assets/skills/code-review-skill/assets/review-checklist.md +123 -0
  18. package/assets/skills/code-review-skill/reference/angular.md +768 -0
  19. package/assets/skills/code-review-skill/reference/architecture-review-guide.md +472 -0
  20. package/assets/skills/code-review-skill/reference/c.md +890 -0
  21. package/assets/skills/code-review-skill/reference/code-quality-universal.md +488 -0
  22. package/assets/skills/code-review-skill/reference/code-review-best-practices.md +136 -0
  23. package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +286 -0
  24. package/assets/skills/code-review-skill/reference/cpp.md +893 -0
  25. package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +515 -0
  26. package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +492 -0
  27. package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +309 -0
  28. package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +308 -0
  29. package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +264 -0
  30. package/assets/skills/code-review-skill/reference/csharp.md +525 -0
  31. package/assets/skills/code-review-skill/reference/css-less-sass.md +661 -0
  32. package/assets/skills/code-review-skill/reference/django.md +985 -0
  33. package/assets/skills/code-review-skill/reference/fastapi.md +580 -0
  34. package/assets/skills/code-review-skill/reference/go.md +993 -0
  35. package/assets/skills/code-review-skill/reference/java.md +409 -0
  36. package/assets/skills/code-review-skill/reference/java8.md +586 -0
  37. package/assets/skills/code-review-skill/reference/kotlin.md +1018 -0
  38. package/assets/skills/code-review-skill/reference/nestjs.md +593 -0
  39. package/assets/skills/code-review-skill/reference/performance-review-guide.md +816 -0
  40. package/assets/skills/code-review-skill/reference/php.md +684 -0
  41. package/assets/skills/code-review-skill/reference/python.md +1073 -0
  42. package/assets/skills/code-review-skill/reference/qt.md +757 -0
  43. package/assets/skills/code-review-skill/reference/react.md +871 -0
  44. package/assets/skills/code-review-skill/reference/ruby.md +964 -0
  45. package/assets/skills/code-review-skill/reference/rust.md +846 -0
  46. package/assets/skills/code-review-skill/reference/security-review-guide.md +494 -0
  47. package/assets/skills/code-review-skill/reference/svelte.md +1064 -0
  48. package/assets/skills/code-review-skill/reference/swift.md +936 -0
  49. package/assets/skills/code-review-skill/reference/typescript.md +1016 -0
  50. package/assets/skills/code-review-skill/reference/vue.md +924 -0
  51. package/assets/skills/code-review-skill/reference/zig.md +440 -0
  52. package/assets/skills/code-review-skill/scripts/pr-analyzer.py +435 -0
  53. package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +380 -0
  54. package/assets/skills/codebase-design/.crosscheck-skill.json +9 -0
  55. package/assets/skills/codebase-design/DEEPENING.md +37 -0
  56. package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  57. package/assets/skills/codebase-design/LICENSE +21 -0
  58. package/assets/skills/codebase-design/SKILL.md +114 -0
  59. package/assets/skills/codebase-design/agents/openai.yaml +3 -0
  60. package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +9 -0
  61. package/assets/skills/diagnosing-bugs/LICENSE +21 -0
  62. package/assets/skills/diagnosing-bugs/SKILL.md +134 -0
  63. package/assets/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  64. package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  65. package/crosscheck.config.example.yml +101 -9
  66. package/dist/__tests__/board.test.js +11 -0
  67. package/dist/__tests__/board.test.js.map +1 -1
  68. package/dist/__tests__/can-write-verdict.test.d.ts +2 -0
  69. package/dist/__tests__/can-write-verdict.test.d.ts.map +1 -0
  70. package/dist/__tests__/can-write-verdict.test.js +31 -0
  71. package/dist/__tests__/can-write-verdict.test.js.map +1 -0
  72. package/dist/__tests__/codex.test.js +14 -27
  73. package/dist/__tests__/codex.test.js.map +1 -1
  74. package/dist/__tests__/comment-bodies.test.js +49 -1
  75. package/dist/__tests__/comment-bodies.test.js.map +1 -1
  76. package/dist/__tests__/conflict-resolve.test.js +44 -1
  77. package/dist/__tests__/conflict-resolve.test.js.map +1 -1
  78. package/dist/__tests__/fix.test.js +33 -0
  79. package/dist/__tests__/fix.test.js.map +1 -1
  80. package/dist/__tests__/linear-branding.test.d.ts +2 -0
  81. package/dist/__tests__/linear-branding.test.d.ts.map +1 -0
  82. package/dist/__tests__/linear-branding.test.js +156 -0
  83. package/dist/__tests__/linear-branding.test.js.map +1 -0
  84. package/dist/__tests__/linear-client.test.d.ts +2 -0
  85. package/dist/__tests__/linear-client.test.d.ts.map +1 -0
  86. package/dist/__tests__/linear-client.test.js +120 -0
  87. package/dist/__tests__/linear-client.test.js.map +1 -0
  88. package/dist/__tests__/linear-comment.test.d.ts +2 -0
  89. package/dist/__tests__/linear-comment.test.d.ts.map +1 -0
  90. package/dist/__tests__/linear-comment.test.js +151 -0
  91. package/dist/__tests__/linear-comment.test.js.map +1 -0
  92. package/dist/__tests__/linear-identity.test.d.ts +2 -0
  93. package/dist/__tests__/linear-identity.test.d.ts.map +1 -0
  94. package/dist/__tests__/linear-identity.test.js +253 -0
  95. package/dist/__tests__/linear-identity.test.js.map +1 -0
  96. package/dist/__tests__/linear-notify.test.d.ts +2 -0
  97. package/dist/__tests__/linear-notify.test.d.ts.map +1 -0
  98. package/dist/__tests__/linear-notify.test.js +144 -0
  99. package/dist/__tests__/linear-notify.test.js.map +1 -0
  100. package/dist/__tests__/linear-ref.test.d.ts +2 -0
  101. package/dist/__tests__/linear-ref.test.d.ts.map +1 -0
  102. package/dist/__tests__/linear-ref.test.js +261 -0
  103. package/dist/__tests__/linear-ref.test.js.map +1 -0
  104. package/dist/__tests__/linear-test-ref.test.d.ts +2 -0
  105. package/dist/__tests__/linear-test-ref.test.d.ts.map +1 -0
  106. package/dist/__tests__/linear-test-ref.test.js +81 -0
  107. package/dist/__tests__/linear-test-ref.test.js.map +1 -0
  108. package/dist/__tests__/linear-verify.test.d.ts +2 -0
  109. package/dist/__tests__/linear-verify.test.d.ts.map +1 -0
  110. package/dist/__tests__/linear-verify.test.js +132 -0
  111. package/dist/__tests__/linear-verify.test.js.map +1 -0
  112. package/dist/__tests__/linear-worker.test.d.ts +2 -0
  113. package/dist/__tests__/linear-worker.test.d.ts.map +1 -0
  114. package/dist/__tests__/linear-worker.test.js +83 -0
  115. package/dist/__tests__/linear-worker.test.js.map +1 -0
  116. package/dist/__tests__/linear-write-possible.test.d.ts +2 -0
  117. package/dist/__tests__/linear-write-possible.test.d.ts.map +1 -0
  118. package/dist/__tests__/linear-write-possible.test.js +30 -0
  119. package/dist/__tests__/linear-write-possible.test.js.map +1 -0
  120. package/dist/__tests__/onboard-preservation.test.js +59 -3
  121. package/dist/__tests__/onboard-preservation.test.js.map +1 -1
  122. package/dist/__tests__/optimize.test.js +2 -0
  123. package/dist/__tests__/optimize.test.js.map +1 -1
  124. package/dist/__tests__/repo-picker.test.js +7 -1
  125. package/dist/__tests__/repo-picker.test.js.map +1 -1
  126. package/dist/__tests__/repository-guidance.test.d.ts +2 -0
  127. package/dist/__tests__/repository-guidance.test.d.ts.map +1 -0
  128. package/dist/__tests__/repository-guidance.test.js +107 -0
  129. package/dist/__tests__/repository-guidance.test.js.map +1 -0
  130. package/dist/__tests__/review-comment-body.test.js +35 -0
  131. package/dist/__tests__/review-comment-body.test.js.map +1 -1
  132. package/dist/__tests__/review-models.test.js +19 -3
  133. package/dist/__tests__/review-models.test.js.map +1 -1
  134. package/dist/__tests__/review-strategy.test.d.ts +2 -0
  135. package/dist/__tests__/review-strategy.test.d.ts.map +1 -0
  136. package/dist/__tests__/review-strategy.test.js +397 -0
  137. package/dist/__tests__/review-strategy.test.js.map +1 -0
  138. package/dist/__tests__/runner.test.js +29 -1
  139. package/dist/__tests__/runner.test.js.map +1 -1
  140. package/dist/__tests__/skill-attribution.test.d.ts +2 -0
  141. package/dist/__tests__/skill-attribution.test.d.ts.map +1 -0
  142. package/dist/__tests__/skill-attribution.test.js +53 -0
  143. package/dist/__tests__/skill-attribution.test.js.map +1 -0
  144. package/dist/__tests__/skill-broker.test.d.ts +2 -0
  145. package/dist/__tests__/skill-broker.test.d.ts.map +1 -0
  146. package/dist/__tests__/skill-broker.test.js +144 -0
  147. package/dist/__tests__/skill-broker.test.js.map +1 -0
  148. package/dist/__tests__/skill-catalog.test.d.ts +2 -0
  149. package/dist/__tests__/skill-catalog.test.d.ts.map +1 -0
  150. package/dist/__tests__/skill-catalog.test.js +40 -0
  151. package/dist/__tests__/skill-catalog.test.js.map +1 -0
  152. package/dist/__tests__/skill-installer.test.d.ts +2 -0
  153. package/dist/__tests__/skill-installer.test.d.ts.map +1 -0
  154. package/dist/__tests__/skill-installer.test.js +96 -0
  155. package/dist/__tests__/skill-installer.test.js.map +1 -0
  156. package/dist/__tests__/skills-config.test.d.ts +2 -0
  157. package/dist/__tests__/skills-config.test.d.ts.map +1 -0
  158. package/dist/__tests__/skills-config.test.js +12 -0
  159. package/dist/__tests__/skills-config.test.js.map +1 -0
  160. package/dist/cli.js +29 -0
  161. package/dist/cli.js.map +1 -1
  162. package/dist/commands/linear-test.d.ts +18 -0
  163. package/dist/commands/linear-test.d.ts.map +1 -0
  164. package/dist/commands/linear-test.js +130 -0
  165. package/dist/commands/linear-test.js.map +1 -0
  166. package/dist/commands/onboard.d.ts +36 -3
  167. package/dist/commands/onboard.d.ts.map +1 -1
  168. package/dist/commands/onboard.js +233 -42
  169. package/dist/commands/onboard.js.map +1 -1
  170. package/dist/commands/review.d.ts.map +1 -1
  171. package/dist/commands/review.js +65 -6
  172. package/dist/commands/review.js.map +1 -1
  173. package/dist/commands/run.d.ts.map +1 -1
  174. package/dist/commands/run.js +45 -7
  175. package/dist/commands/run.js.map +1 -1
  176. package/dist/commands/skill.d.ts +2 -0
  177. package/dist/commands/skill.d.ts.map +1 -0
  178. package/dist/commands/skill.js +16 -0
  179. package/dist/commands/skill.js.map +1 -0
  180. package/dist/commands/status.d.ts.map +1 -1
  181. package/dist/commands/status.js +53 -1
  182. package/dist/commands/status.js.map +1 -1
  183. package/dist/commands/watch.d.ts.map +1 -1
  184. package/dist/commands/watch.js +90 -12
  185. package/dist/commands/watch.js.map +1 -1
  186. package/dist/config/loader.d.ts +3 -1
  187. package/dist/config/loader.d.ts.map +1 -1
  188. package/dist/config/loader.js +13 -0
  189. package/dist/config/loader.js.map +1 -1
  190. package/dist/config/review-model-tiers.json +3 -3
  191. package/dist/config/review-strategy.json +204 -0
  192. package/dist/config/schema.d.ts +261 -15
  193. package/dist/config/schema.d.ts.map +1 -1
  194. package/dist/config/schema.js +90 -8
  195. package/dist/config/schema.js.map +1 -1
  196. package/dist/github/client.d.ts +21 -1
  197. package/dist/github/client.d.ts.map +1 -1
  198. package/dist/github/client.js +46 -7
  199. package/dist/github/client.js.map +1 -1
  200. package/dist/github/webhook.d.ts +4 -0
  201. package/dist/github/webhook.d.ts.map +1 -1
  202. package/dist/github/webhook.js.map +1 -1
  203. package/dist/issues/ticket-ref.d.ts.map +1 -1
  204. package/dist/issues/ticket-ref.js +6 -5
  205. package/dist/issues/ticket-ref.js.map +1 -1
  206. package/dist/lib/annotation.d.ts +7 -0
  207. package/dist/lib/annotation.d.ts.map +1 -1
  208. package/dist/lib/annotation.js +11 -1
  209. package/dist/lib/annotation.js.map +1 -1
  210. package/dist/lib/board.d.ts +3 -0
  211. package/dist/lib/board.d.ts.map +1 -1
  212. package/dist/lib/board.js +4 -2
  213. package/dist/lib/board.js.map +1 -1
  214. package/dist/lib/clone.d.ts +1 -0
  215. package/dist/lib/clone.d.ts.map +1 -1
  216. package/dist/lib/clone.js +32 -10
  217. package/dist/lib/clone.js.map +1 -1
  218. package/dist/lib/comment-bodies.d.ts +37 -0
  219. package/dist/lib/comment-bodies.d.ts.map +1 -1
  220. package/dist/lib/comment-bodies.js +47 -9
  221. package/dist/lib/comment-bodies.js.map +1 -1
  222. package/dist/lib/repo-picker.d.ts +3 -0
  223. package/dist/lib/repo-picker.d.ts.map +1 -1
  224. package/dist/lib/repo-picker.js +45 -9
  225. package/dist/lib/repo-picker.js.map +1 -1
  226. package/dist/lib/repository-guidance.d.ts +2 -0
  227. package/dist/lib/repository-guidance.d.ts.map +1 -0
  228. package/dist/lib/repository-guidance.js +55 -0
  229. package/dist/lib/repository-guidance.js.map +1 -0
  230. package/dist/lib/review-models.d.ts +15 -2
  231. package/dist/lib/review-models.d.ts.map +1 -1
  232. package/dist/lib/review-models.js +26 -6
  233. package/dist/lib/review-models.js.map +1 -1
  234. package/dist/lib/review-strategy.d.ts +92 -0
  235. package/dist/lib/review-strategy.d.ts.map +1 -0
  236. package/dist/lib/review-strategy.js +282 -0
  237. package/dist/lib/review-strategy.js.map +1 -0
  238. package/dist/lib/runner.d.ts +92 -0
  239. package/dist/lib/runner.d.ts.map +1 -1
  240. package/dist/lib/runner.js +470 -54
  241. package/dist/lib/runner.js.map +1 -1
  242. package/dist/lib/workflow.d.ts +9 -0
  243. package/dist/lib/workflow.d.ts.map +1 -1
  244. package/dist/lib/workflow.js +20 -0
  245. package/dist/lib/workflow.js.map +1 -1
  246. package/dist/linear/client.d.ts +18 -0
  247. package/dist/linear/client.d.ts.map +1 -0
  248. package/dist/linear/client.js +67 -0
  249. package/dist/linear/client.js.map +1 -0
  250. package/dist/linear/comment.d.ts +20 -0
  251. package/dist/linear/comment.d.ts.map +1 -0
  252. package/dist/linear/comment.js +57 -0
  253. package/dist/linear/comment.js.map +1 -0
  254. package/dist/linear/identity.d.ts +59 -0
  255. package/dist/linear/identity.d.ts.map +1 -0
  256. package/dist/linear/identity.js +187 -0
  257. package/dist/linear/identity.js.map +1 -0
  258. package/dist/linear/notify.d.ts +35 -0
  259. package/dist/linear/notify.d.ts.map +1 -0
  260. package/dist/linear/notify.js +76 -0
  261. package/dist/linear/notify.js.map +1 -0
  262. package/dist/linear/ref.d.ts +13 -0
  263. package/dist/linear/ref.d.ts.map +1 -0
  264. package/dist/linear/ref.js +90 -0
  265. package/dist/linear/ref.js.map +1 -0
  266. package/dist/linear/verify.d.ts +26 -0
  267. package/dist/linear/verify.d.ts.map +1 -0
  268. package/dist/linear/verify.js +67 -0
  269. package/dist/linear/verify.js.map +1 -0
  270. package/dist/reviewers/claude.d.ts +4 -1
  271. package/dist/reviewers/claude.d.ts.map +1 -1
  272. package/dist/reviewers/claude.js +39 -7
  273. package/dist/reviewers/claude.js.map +1 -1
  274. package/dist/reviewers/codex.d.ts +3 -1
  275. package/dist/reviewers/codex.d.ts.map +1 -1
  276. package/dist/reviewers/codex.js +76 -70
  277. package/dist/reviewers/codex.js.map +1 -1
  278. package/dist/reviewers/conflict-resolve.d.ts +3 -1
  279. package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
  280. package/dist/reviewers/conflict-resolve.js +21 -6
  281. package/dist/reviewers/conflict-resolve.js.map +1 -1
  282. package/dist/reviewers/fix.d.ts +5 -2
  283. package/dist/reviewers/fix.d.ts.map +1 -1
  284. package/dist/reviewers/fix.js +26 -10
  285. package/dist/reviewers/fix.js.map +1 -1
  286. package/dist/skills/attribution.d.ts +4 -0
  287. package/dist/skills/attribution.d.ts.map +1 -0
  288. package/dist/skills/attribution.js +14 -0
  289. package/dist/skills/attribution.js.map +1 -0
  290. package/dist/skills/broker-server.d.ts +2 -0
  291. package/dist/skills/broker-server.d.ts.map +1 -0
  292. package/dist/skills/broker-server.js +17 -0
  293. package/dist/skills/broker-server.js.map +1 -0
  294. package/dist/skills/broker.d.ts +42 -0
  295. package/dist/skills/broker.d.ts.map +1 -0
  296. package/dist/skills/broker.js +285 -0
  297. package/dist/skills/broker.js.map +1 -0
  298. package/dist/skills/catalog.d.ts +28 -0
  299. package/dist/skills/catalog.d.ts.map +1 -0
  300. package/dist/skills/catalog.js +104 -0
  301. package/dist/skills/catalog.js.map +1 -0
  302. package/dist/skills/installer.d.ts +10 -0
  303. package/dist/skills/installer.d.ts.map +1 -0
  304. package/dist/skills/installer.js +138 -0
  305. package/dist/skills/installer.js.map +1 -0
  306. package/dist/skills/integrity.d.ts +4 -0
  307. package/dist/skills/integrity.d.ts.map +1 -0
  308. package/dist/skills/integrity.js +36 -0
  309. package/dist/skills/integrity.js.map +1 -0
  310. package/docs/dynamic-thoroughness.md +738 -0
  311. package/docs/linear-identity-contract.md +139 -0
  312. package/docs/linear-identity.md +293 -0
  313. package/get-started.md +207 -11
  314. package/package.json +4 -3
@@ -1,18 +1,37 @@
1
1
  import { execSync } from 'child_process';
2
2
  import { existsSync, statSync } from 'fs';
3
3
  import chalk from 'chalk';
4
- import { loadConfig, getGithubTokenSource, getWebhookSecretPath, resolveConfigPath } from '../config/loader.js';
4
+ import { loadConfig, getGithubTokenSource, getWebhookSecretPath, resolveConfigPath, getLinearCredentials } from '../config/loader.js';
5
+ import { verifyLinearIdentity } from '../linear/verify.js';
5
6
  import { checkCodexAuth } from '../reviewers/codex.js';
6
7
  import { checkClaudeAuth } from '../reviewers/claude.js';
7
8
  import { getLogDir, getTodayLogPath } from '../lib/logger.js';
8
9
  import { buildImpactReport } from './impact.js';
10
+ import { formatSkillIdentity, loadSkillCatalog } from '../skills/catalog.js';
9
11
  function row(label, value, ok) {
10
12
  const indicator = ok === undefined ? ' ' : ok ? chalk.green('✓') : chalk.red('✗');
11
13
  console.log(` ${indicator} ${chalk.bold(label.padEnd(22))} ${value}`);
12
14
  }
15
+ const LINEAR_PROBE_TIMEOUT_MS = 10_000;
13
16
  export async function runStatus(configPath) {
14
17
  const config = loadConfig(configPath);
15
18
  const activeConfigPath = resolveConfigPath(configPath);
19
+ // Start the Linear probe before the CLI auth checks so the two network round
20
+ // trips overlap, and bound it — status must stay responsive even if Linear is
21
+ // slow or unreachable. verifyLinearIdentity never throws; the timeout is the
22
+ // only way this can reject, so it resolves to a report either way.
23
+ const linearProbe = config.linear.enabled
24
+ ? Promise.race([
25
+ verifyLinearIdentity(config.linear, getLinearCredentials(config.linear.auth)),
26
+ new Promise(resolve => setTimeout(() => resolve({
27
+ ok: false,
28
+ mode: config.linear.auth.mode,
29
+ actor: config.linear.identity.actor,
30
+ attribution: config.linear.auth.mode === 'client_credentials' ? 'app' : 'user',
31
+ error: `timed out after ${LINEAR_PROBE_TIMEOUT_MS / 1000}s`,
32
+ }), LINEAR_PROBE_TIMEOUT_MS).unref?.()),
33
+ ])
34
+ : null;
16
35
  console.log(chalk.bold('\ncrosscheck status\n'));
17
36
  // Auth
18
37
  console.log(chalk.dim(' Auth'));
@@ -38,6 +57,15 @@ export async function runStatus(configPath) {
38
57
  row('config path', activeConfigPath ?? 'defaults only');
39
58
  row('mode', config.mode);
40
59
  row('quality tier', config.quality.tier);
60
+ const skillCatalog = loadSkillCatalog();
61
+ const bundledSkills = new Map(skillCatalog.map(skill => [skill.name, skill]));
62
+ row('installed skills', skillCatalog.map(formatSkillIdentity).join(', '));
63
+ row('enabled skills', config.skills.enabled.length > 0
64
+ ? config.skills.enabled.map(name => {
65
+ const skill = bundledSkills.get(name);
66
+ return skill ? formatSkillIdentity(skill) : `${name} (not installed or failed integrity check)`;
67
+ }).join(', ')
68
+ : 'none');
41
69
  row('codex auth', config.vendors.codex.auth);
42
70
  row('codex model', config.vendors.codex.model ?? 'auto (by tier)');
43
71
  row('claude model', config.vendors.claude.model ?? 'default');
@@ -50,6 +78,30 @@ export async function runStatus(configPath) {
50
78
  if (config.quality.focus.length > 0) {
51
79
  row('focus', config.quality.focus.join(', '));
52
80
  }
81
+ // Linear identity — only when the operator has opted in.
82
+ if (linearProbe) {
83
+ console.log();
84
+ console.log(chalk.dim(' Linear'));
85
+ const report = await linearProbe;
86
+ row('auth mode', report.mode, report.ok);
87
+ if (!report.ok) {
88
+ row('identity', report.error ?? 'verification failed', false);
89
+ }
90
+ else {
91
+ row('organization', report.organization ?? 'unknown');
92
+ if (report.attribution === 'app') {
93
+ const actor = config.linear.identity.per_step_actor ? `${report.actor}/<step>` : report.actor;
94
+ row('writes as', `${actor} ${chalk.dim('(crosscheck itself)')}`, true);
95
+ }
96
+ else {
97
+ // Deliberately not a failed check. Attributing to a person is the wrong
98
+ // state for a shared workspace, but it is a perfectly reasonable choice for
99
+ // a solo user with no attribution problem — so this informs, it does not nag.
100
+ row('writes as', `${report.attributesTo ?? 'your Linear account'} ${chalk.dim('(api key)')}`);
101
+ console.log(chalk.dim(' to post as crosscheck itself, see docs/linear-identity.md'));
102
+ }
103
+ }
104
+ }
53
105
  // Logs
54
106
  console.log();
55
107
  console.log(chalk.dim(' Logs'));
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAyKA,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,SAAc,iBAqvClD"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AA2KA,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,SAAc,iBAs0ClD"}
@@ -3,18 +3,19 @@ import chalk from 'chalk';
3
3
  import { createWebhookServer } from '../github/webhook.js';
4
4
  import { createGithubClient, getCommitMessage, registerOrgWebhook, deleteOrgWebhook, registerRepoWebhook, deleteRepoWebhook, patchOrgWebhookEvents, patchRepoWebhookEvents, findOrgWebhook, findRepoWebhook, listUserRepos, checkRepoAccessible, } from '../github/client.js';
5
5
  import { detectOriginFull, assignReviewer } from '../github/detector.js';
6
- import { loadConfig, getGithubToken, getWebhookSecret, resolveConfigPath, promptDeploymentMode, detectScopesForDeployment, patchDeploymentConfig, detectGitHubLogin, } from '../config/loader.js';
6
+ import { loadConfig, getGithubToken, getWebhookSecret, resolveConfigPath, promptDeploymentMode, detectScopesForDeployment, patchDeploymentConfig, detectGitHubLogin, getLinearCredentials, } from '../config/loader.js';
7
7
  import { randomFortune } from '../lib/fortune.js';
8
8
  import { scanUnreviewedPRs } from '../lib/backtrace.js';
9
9
  import { initLogger, log as fileLog, logError, logUncaught } from '../lib/logger.js';
10
10
  import { isAuthorAllowed } from '../lib/filter.js';
11
11
  import { runWorkflow } from '../lib/runner.js';
12
- import { loadWorkflow, DEFAULT_RECHECK_INSTRUCTIONS } from '../lib/workflow.js';
12
+ import { loadWorkflow, linearWritePossible, DEFAULT_RECHECK_INSTRUCTIONS } from '../lib/workflow.js';
13
13
  import { filterStepsByTypes, formatRepoWorkflowSteps, isRecheckWithoutFix, isReviewOnlyWorkflow, readRepoWorkflowStepTypes, resolveRepoWorkflowSteps, workflowHasStep } from '../lib/repo-workflow.js';
14
14
  import { fetchStepHistory, identifyNextWorkflowStep, decideReviewOnly } from '../lib/pr-workflow-state.js';
15
15
  import { parseAnnotation } from '../lib/annotation.js';
16
16
  import { PRBoard, fmtTime, FMT_TIME_WIDTH } from '../lib/board.js';
17
17
  import { clonePRForReview } from '../lib/clone.js';
18
+ import { resolveLinearAuth, isLinearConfigError } from '../linear/identity.js';
18
19
  import { getSmartSwitch, isSubscriptionLimitError, detectFailedVendor, triggerSwitch, notifyReviewSuccess, stopSmartSwitch, } from '../lib/smart-switch.js';
19
20
  import { buildReviewFailedCommentBody } from '../lib/comment-bodies.js';
20
21
  import { classifyReviewerError } from '../lib/reviewer-error.js';
@@ -156,6 +157,25 @@ export async function runWatch(opts = {}) {
156
157
  console.error(chalk.red(`✗ ${err instanceof Error ? err.message : String(err)}`));
157
158
  process.exit(1);
158
159
  }
160
+ // Preflight Linear identity at startup. watch is a long-running daemon: a bad
161
+ // credential discovered per-event would either drop events silently or spam the
162
+ // board. Fail loudly at boot instead, the way the run path fails before its
163
+ // clone. The token is discarded — per-event resolution mints a fresh one, since
164
+ // app tokens outlive neither a long daemon run nor a rotation.
165
+ // Same gate as the run and per-event paths: a daemon whose configured workflow
166
+ // is fix/conflict-resolve only can never call notifyLinear, so a missing
167
+ // credential must not stop it booting.
168
+ if (linearWritePossible(config.linear, loadWorkflow(process.cwd()))) {
169
+ try {
170
+ const preflight = await resolveLinearAuth(config.linear, getLinearCredentials(config.linear.auth));
171
+ console.log(chalk.dim(` linear: ${preflight.mode} — writes as ${preflight.actor}`));
172
+ }
173
+ catch (err) {
174
+ logError({ command: 'watch', phase: 'linear-auth' }, err);
175
+ console.error(chalk.red(`✗ ${err instanceof Error ? err.message : String(err)}`));
176
+ process.exit(isLinearConfigError(err) ? 1 : 2);
177
+ }
178
+ }
159
179
  fileLog({ level: 'info', event: 'session_start', command: 'watch' });
160
180
  // Fetch the authenticated user so the onComment handler can reject annotation
161
181
  // injection from non-token accounts. If this fails, the handler is disabled
@@ -235,9 +255,16 @@ export async function runWatch(opts = {}) {
235
255
  title: params.title,
236
256
  body: params.body ?? '',
237
257
  head: { ref: params.headRef, sha: params.headSha, repo: params.headRepo ? { full_name: params.headRepo } : null },
238
- base: { ref: params.baseRef, repo: { full_name: `${owner}/${repoName}` } },
258
+ base: {
259
+ ref: params.baseRef,
260
+ repo: {
261
+ full_name: `${owner}/${repoName}`,
262
+ ...(params.defaultBranch !== undefined && { default_branch: params.defaultBranch }),
263
+ },
264
+ },
239
265
  html_url: `https://github.com/${owner}/${repoName}/pull/${prNumber}`,
240
266
  user: { login: params.author },
267
+ ...(params.labels !== undefined && { labels: params.labels.map(name => ({ name })) }),
241
268
  };
242
269
  if (!acquirePRLock(owner, repoName, prNumber, params.headSha)) {
243
270
  fileLog({ level: 'info', event: 'pr_skipped', repo: `${owner}/${repoName}`, pr: prNumber, reason: 'in_progress_local' });
@@ -407,6 +434,32 @@ export async function runWatch(opts = {}) {
407
434
  let stopHeartbeat = () => { };
408
435
  let boardAdded = false;
409
436
  try {
437
+ // Board first, so any failure below is visible rather than swallowed by the
438
+ // enclosing catch (which only calls logError — a no-op when file logging is
439
+ // off). Then auth, then the clone: during an outage a long-running watcher
440
+ // would otherwise pay for a full clone on every event before rejecting it.
441
+ // Computed here rather than at the runWorkflow call so the auth gate below
442
+ // sees the workflow that will actually run. resolvedSteps alone is
443
+ // undefined for a plain event, and canWriteVerdict fails open on undefined
444
+ // — which let a fix-only daemon resolve credentials on every event.
445
+ const workflowStepsForRun = resolvedSteps
446
+ ?? (repoStepOverride ? filterStepsByTypes(loadWorkflow(process.cwd()), repoStepOverride) : loadWorkflow(process.cwd()));
447
+ board.addPR(key, prNumber, `${owner}/${repoName}`, params.headRef, round);
448
+ boardAdded = true;
449
+ // Only workflows that can write a verdict need an identity — the fix and
450
+ // resolve paths never call notifyLinear.
451
+ let linearAuth = null;
452
+ if (linearWritePossible(effectiveConfig.linear, workflowStepsForRun)) {
453
+ try {
454
+ linearAuth = await resolveLinearAuth(effectiveConfig.linear, getLinearCredentials(effectiveConfig.linear.auth));
455
+ }
456
+ catch (err) {
457
+ const message = err instanceof Error ? err.message : String(err);
458
+ board.failPR(key, `linear identity unavailable: ${message}`);
459
+ fileLog({ level: 'error', event: 'linear_auth_failed', repo: `${owner}/${repoName}`, pr: prNumber, reason: message });
460
+ throw err;
461
+ }
462
+ }
410
463
  await clonePRForReview({
411
464
  owner, repo: repoName, prNumber, baseRef: params.baseRef,
412
465
  tmpDir, token, protocol: config.clone_protocol,
@@ -442,18 +495,18 @@ export async function runWatch(opts = {}) {
442
495
  logError({ repo: `${owner}/${repoName}`, pr: prNumber, phase: 'no_diff_comment' }, err);
443
496
  }
444
497
  await releaseRemoteLock(lockOctokit, owner, repoName, params.headSha, 'success');
498
+ // The PR is on the board from before the clone, so close its slot rather
499
+ // than leaving a row that never resolves.
500
+ board.completePR(key, { elapsedMs: Date.now() - reviewStart, url: `https://github.com/${owner}/${repoName}/pull/${prNumber}` });
445
501
  return;
446
502
  }
447
- board.addPR(key, prNumber, `${owner}/${repoName}`, params.headRef, round);
448
- boardAdded = true;
449
503
  const prLoc = computePRLoc(tmpDir, params.baseRef);
450
504
  board.updatePR(key, { prLoc });
451
505
  stopHeartbeat = startRemoteLockHeartbeat(lockOctokit, owner, repoName, params.headSha);
452
- const workflowStepsForRun = resolvedSteps
453
- ?? (repoStepOverride ? filterStepsByTypes(loadWorkflow(process.cwd()), repoStepOverride) : undefined);
454
- const { verdict, fixAppliedCount } = await runWorkflow({
506
+ const { verdict, fixAppliedCount, strategySkipped } = await runWorkflow({
455
507
  owner, repoName, prNumber, pr,
456
508
  tmpDir, token, config: effectiveConfig, origin,
509
+ linearAuth,
457
510
  reviewStart,
458
511
  log: (msg) => bLog(`${chalk.dim(fmtTime())} ${msg}`),
459
512
  onPhaseChange: (label, data) => board.updatePR(key, { label, ...data }),
@@ -471,9 +524,16 @@ export async function runWatch(opts = {}) {
471
524
  trigger: params.action === 'backtrace' ? 'backtrace' : params.action === 'comment' ? 'comment' : 'watch',
472
525
  });
473
526
  void verdict;
474
- reviewedPRKeys.add(prKey);
475
- reviewedPRShaKeys.add(key); // key = "owner/repo#pr@sha"
476
- prRoundCounts.set(prKey, round);
527
+ // A strategy-skipped PR never ran a review, so it must stay out of the
528
+ // session caches. reviewedPRKeys is what makes the next event on this PR
529
+ // an `isRecheckRun`, and a review coerced to a recheck is deliberately
530
+ // never gated by max_rounds — so a lockfile-only PR that later gains
531
+ // source files would be "rechecked" against findings never posted.
532
+ if (strategySkipped === undefined) {
533
+ reviewedPRKeys.add(prKey);
534
+ reviewedPRShaKeys.add(key); // key = "owner/repo#pr@sha"
535
+ prRoundCounts.set(prKey, round);
536
+ }
477
537
  // Recompute the diff hash AFTER runWorkflow — workflow steps such as
478
538
  // `conflict-resolve` or `fix` followed by `recheck` can mutate the checkout,
479
539
  // so the pre-workflow hash may not represent the content that was actually
@@ -493,7 +553,10 @@ export async function runWatch(opts = {}) {
493
553
  }
494
554
  catch { /* fall back — skip auto-loop this cycle */ }
495
555
  }
496
- if (newDiffHash) {
556
+ // Same gate as the session caches above: caching the diff of a PR that was
557
+ // never reviewed would make the first event that *should* review it get
558
+ // skipped as `no_diff_change`.
559
+ if (newDiffHash && strategySkipped === undefined) {
497
560
  // For non-commit delivery with an applied fix the checkout may be on a fix
498
561
  // branch; computeDiffHash would return the post-fix diff, not the original PR
499
562
  // diff. Caching that under prKey corrupts future no_diff_change checks for the
@@ -514,9 +577,15 @@ export async function runWatch(opts = {}) {
514
577
  }
515
578
  }
516
579
  }
580
+ // A class-skipped PR (e.g. lockfile-only) never ran a review, so say so
581
+ // rather than reporting it as a completed one.
582
+ if (strategySkipped) {
583
+ bLog(`${chalk.dim(fmtTime())} ${chalk.dim(`PR #${prNumber} skipped — ${strategySkipped} class, nothing to review`)}`);
584
+ }
517
585
  board.completePR(key, {
518
586
  elapsedMs: Date.now() - reviewStart,
519
587
  url: `github.com/${owner}/${repoName}/pull/${prNumber}`,
588
+ ...(strategySkipped !== undefined && { label: `skipped · ${strategySkipped}` }),
520
589
  });
521
590
  // Smart-switch recovery confirmation: if a restore attempt is pending and
522
591
  // this reviewer matches the previously-degraded vendor, announce full restoration.
@@ -649,6 +718,8 @@ export async function runWatch(opts = {}) {
649
718
  title: pr.title, body: pr.body, author: pr.user.login,
650
719
  headSha: pr.head.sha, headRef: pr.head.ref, headRepo: pr.head.repo?.full_name ?? null,
651
720
  baseRef: pr.base.ref, action: event.action,
721
+ ...(pr.labels !== undefined && { labels: pr.labels.map(l => l.name) }),
722
+ ...(pr.base.repo.default_branch !== undefined && { defaultBranch: pr.base.repo.default_branch }),
652
723
  });
653
724
  }, (msg) => bLog(chalk.dim(fmtTime()) + ' ' + msg), fileLog, async (event) => {
654
725
  const owner = event.repository.owner.login;
@@ -743,6 +814,11 @@ export async function runWatch(opts = {}) {
743
814
  headRepo: prData.head.repo?.full_name ?? null,
744
815
  baseRef: prData.base.ref,
745
816
  action: 'comment',
817
+ // Same fields the webhook path forwards: without them the risky
818
+ // class's label and hotfix rules classify this PR differently
819
+ // depending on which trigger ran it.
820
+ ...(prData.labels !== undefined && { labels: prData.labels.map((l) => l.name) }),
821
+ ...(prData.base.repo?.default_branch !== undefined && { defaultBranch: prData.base.repo.default_branch }),
746
822
  });
747
823
  break;
748
824
  }
@@ -1029,6 +1105,8 @@ export async function runWatch(opts = {}) {
1029
1105
  title: pr.title, body: pr.body, author: pr.author,
1030
1106
  headSha: pr.headSha, headRef: pr.headRef, headRepo: pr.headRepo,
1031
1107
  baseRef: pr.baseRef, action: 'backtrace',
1108
+ ...(pr.labels !== undefined && { labels: pr.labels }),
1109
+ ...(pr.defaultBranch !== undefined && { defaultBranch: pr.defaultBranch }),
1032
1110
  })));
1033
1111
  }
1034
1112
  catch (err) {