@humanbased/crosscheck 1.2.0-beta.81 โ†’ 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +375 -182
  3. package/README.zh.md +1 -1
  4. package/crosscheck.config.example.yml +9 -101
  5. package/dist/__tests__/board.test.js +0 -11
  6. package/dist/__tests__/board.test.js.map +1 -1
  7. package/dist/__tests__/codex.test.js +27 -14
  8. package/dist/__tests__/codex.test.js.map +1 -1
  9. package/dist/__tests__/comment-bodies.test.js +1 -49
  10. package/dist/__tests__/comment-bodies.test.js.map +1 -1
  11. package/dist/__tests__/conflict-resolve.test.js +1 -44
  12. package/dist/__tests__/conflict-resolve.test.js.map +1 -1
  13. package/dist/__tests__/fix.test.js +0 -33
  14. package/dist/__tests__/fix.test.js.map +1 -1
  15. package/dist/__tests__/onboard-preservation.test.js +3 -59
  16. package/dist/__tests__/onboard-preservation.test.js.map +1 -1
  17. package/dist/__tests__/optimize.test.js +0 -2
  18. package/dist/__tests__/optimize.test.js.map +1 -1
  19. package/dist/__tests__/repo-picker.test.js +1 -7
  20. package/dist/__tests__/repo-picker.test.js.map +1 -1
  21. package/dist/__tests__/review-comment-body.test.js +0 -35
  22. package/dist/__tests__/review-comment-body.test.js.map +1 -1
  23. package/dist/__tests__/review-models.test.js +3 -19
  24. package/dist/__tests__/review-models.test.js.map +1 -1
  25. package/dist/__tests__/runner.test.js +1 -29
  26. package/dist/__tests__/runner.test.js.map +1 -1
  27. package/dist/cli.js +0 -29
  28. package/dist/cli.js.map +1 -1
  29. package/dist/commands/onboard.d.ts +3 -36
  30. package/dist/commands/onboard.d.ts.map +1 -1
  31. package/dist/commands/onboard.js +42 -233
  32. package/dist/commands/onboard.js.map +1 -1
  33. package/dist/commands/review.d.ts.map +1 -1
  34. package/dist/commands/review.js +6 -65
  35. package/dist/commands/review.js.map +1 -1
  36. package/dist/commands/run.d.ts.map +1 -1
  37. package/dist/commands/run.js +7 -45
  38. package/dist/commands/run.js.map +1 -1
  39. package/dist/commands/status.d.ts.map +1 -1
  40. package/dist/commands/status.js +1 -53
  41. package/dist/commands/status.js.map +1 -1
  42. package/dist/commands/watch.d.ts.map +1 -1
  43. package/dist/commands/watch.js +12 -90
  44. package/dist/commands/watch.js.map +1 -1
  45. package/dist/config/loader.d.ts +1 -3
  46. package/dist/config/loader.d.ts.map +1 -1
  47. package/dist/config/loader.js +0 -13
  48. package/dist/config/loader.js.map +1 -1
  49. package/dist/config/review-model-tiers.json +3 -3
  50. package/dist/config/schema.d.ts +15 -261
  51. package/dist/config/schema.d.ts.map +1 -1
  52. package/dist/config/schema.js +8 -90
  53. package/dist/config/schema.js.map +1 -1
  54. package/dist/github/client.d.ts +1 -21
  55. package/dist/github/client.d.ts.map +1 -1
  56. package/dist/github/client.js +7 -46
  57. package/dist/github/client.js.map +1 -1
  58. package/dist/github/webhook.d.ts +0 -4
  59. package/dist/github/webhook.d.ts.map +1 -1
  60. package/dist/github/webhook.js.map +1 -1
  61. package/dist/issues/ticket-ref.d.ts.map +1 -1
  62. package/dist/issues/ticket-ref.js +5 -6
  63. package/dist/issues/ticket-ref.js.map +1 -1
  64. package/dist/lib/annotation.d.ts +0 -7
  65. package/dist/lib/annotation.d.ts.map +1 -1
  66. package/dist/lib/annotation.js +1 -11
  67. package/dist/lib/annotation.js.map +1 -1
  68. package/dist/lib/board.d.ts +0 -3
  69. package/dist/lib/board.d.ts.map +1 -1
  70. package/dist/lib/board.js +2 -4
  71. package/dist/lib/board.js.map +1 -1
  72. package/dist/lib/clone.d.ts +0 -1
  73. package/dist/lib/clone.d.ts.map +1 -1
  74. package/dist/lib/clone.js +10 -32
  75. package/dist/lib/clone.js.map +1 -1
  76. package/dist/lib/comment-bodies.d.ts +0 -37
  77. package/dist/lib/comment-bodies.d.ts.map +1 -1
  78. package/dist/lib/comment-bodies.js +9 -47
  79. package/dist/lib/comment-bodies.js.map +1 -1
  80. package/dist/lib/repo-picker.d.ts +0 -3
  81. package/dist/lib/repo-picker.d.ts.map +1 -1
  82. package/dist/lib/repo-picker.js +9 -45
  83. package/dist/lib/repo-picker.js.map +1 -1
  84. package/dist/lib/review-models.d.ts +2 -15
  85. package/dist/lib/review-models.d.ts.map +1 -1
  86. package/dist/lib/review-models.js +6 -26
  87. package/dist/lib/review-models.js.map +1 -1
  88. package/dist/lib/runner.d.ts +0 -92
  89. package/dist/lib/runner.d.ts.map +1 -1
  90. package/dist/lib/runner.js +54 -470
  91. package/dist/lib/runner.js.map +1 -1
  92. package/dist/lib/workflow.d.ts +0 -9
  93. package/dist/lib/workflow.d.ts.map +1 -1
  94. package/dist/lib/workflow.js +0 -20
  95. package/dist/lib/workflow.js.map +1 -1
  96. package/dist/reviewers/claude.d.ts +1 -4
  97. package/dist/reviewers/claude.d.ts.map +1 -1
  98. package/dist/reviewers/claude.js +7 -39
  99. package/dist/reviewers/claude.js.map +1 -1
  100. package/dist/reviewers/codex.d.ts +1 -3
  101. package/dist/reviewers/codex.d.ts.map +1 -1
  102. package/dist/reviewers/codex.js +70 -76
  103. package/dist/reviewers/codex.js.map +1 -1
  104. package/dist/reviewers/conflict-resolve.d.ts +1 -3
  105. package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
  106. package/dist/reviewers/conflict-resolve.js +6 -21
  107. package/dist/reviewers/conflict-resolve.js.map +1 -1
  108. package/dist/reviewers/fix.d.ts +2 -5
  109. package/dist/reviewers/fix.d.ts.map +1 -1
  110. package/dist/reviewers/fix.js +10 -26
  111. package/dist/reviewers/fix.js.map +1 -1
  112. package/get-started.md +11 -207
  113. package/package.json +3 -4
  114. package/assets/icon-256.png +0 -0
  115. package/assets/linear-comment.svg +0 -18
  116. package/assets/linear-onboard.svg +0 -30
  117. package/assets/linear-status.svg +0 -23
  118. package/assets/linear-test.svg +0 -34
  119. package/assets/skills/code-review/.crosscheck-skill.json +0 -9
  120. package/assets/skills/code-review/LICENSE +0 -21
  121. package/assets/skills/code-review/SKILL.md +0 -89
  122. package/assets/skills/code-review/agents/openai.yaml +0 -3
  123. package/assets/skills/code-review-skill/.crosscheck-skill.json +0 -9
  124. package/assets/skills/code-review-skill/LICENSE +0 -21
  125. package/assets/skills/code-review-skill/SKILL.md +0 -231
  126. package/assets/skills/code-review-skill/assets/pr-review-template.md +0 -137
  127. package/assets/skills/code-review-skill/assets/review-checklist.md +0 -123
  128. package/assets/skills/code-review-skill/reference/angular.md +0 -768
  129. package/assets/skills/code-review-skill/reference/architecture-review-guide.md +0 -472
  130. package/assets/skills/code-review-skill/reference/c.md +0 -890
  131. package/assets/skills/code-review-skill/reference/code-quality-universal.md +0 -488
  132. package/assets/skills/code-review-skill/reference/code-review-best-practices.md +0 -136
  133. package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +0 -286
  134. package/assets/skills/code-review-skill/reference/cpp.md +0 -893
  135. package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +0 -515
  136. package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +0 -492
  137. package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +0 -309
  138. package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +0 -308
  139. package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +0 -264
  140. package/assets/skills/code-review-skill/reference/csharp.md +0 -525
  141. package/assets/skills/code-review-skill/reference/css-less-sass.md +0 -661
  142. package/assets/skills/code-review-skill/reference/django.md +0 -985
  143. package/assets/skills/code-review-skill/reference/fastapi.md +0 -580
  144. package/assets/skills/code-review-skill/reference/go.md +0 -993
  145. package/assets/skills/code-review-skill/reference/java.md +0 -409
  146. package/assets/skills/code-review-skill/reference/java8.md +0 -586
  147. package/assets/skills/code-review-skill/reference/kotlin.md +0 -1018
  148. package/assets/skills/code-review-skill/reference/nestjs.md +0 -593
  149. package/assets/skills/code-review-skill/reference/performance-review-guide.md +0 -816
  150. package/assets/skills/code-review-skill/reference/php.md +0 -684
  151. package/assets/skills/code-review-skill/reference/python.md +0 -1073
  152. package/assets/skills/code-review-skill/reference/qt.md +0 -757
  153. package/assets/skills/code-review-skill/reference/react.md +0 -871
  154. package/assets/skills/code-review-skill/reference/ruby.md +0 -964
  155. package/assets/skills/code-review-skill/reference/rust.md +0 -846
  156. package/assets/skills/code-review-skill/reference/security-review-guide.md +0 -494
  157. package/assets/skills/code-review-skill/reference/svelte.md +0 -1064
  158. package/assets/skills/code-review-skill/reference/swift.md +0 -936
  159. package/assets/skills/code-review-skill/reference/typescript.md +0 -1016
  160. package/assets/skills/code-review-skill/reference/vue.md +0 -924
  161. package/assets/skills/code-review-skill/reference/zig.md +0 -440
  162. package/assets/skills/code-review-skill/scripts/pr-analyzer.py +0 -435
  163. package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +0 -380
  164. package/assets/skills/codebase-design/.crosscheck-skill.json +0 -9
  165. package/assets/skills/codebase-design/DEEPENING.md +0 -37
  166. package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +0 -44
  167. package/assets/skills/codebase-design/LICENSE +0 -21
  168. package/assets/skills/codebase-design/SKILL.md +0 -114
  169. package/assets/skills/codebase-design/agents/openai.yaml +0 -3
  170. package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +0 -9
  171. package/assets/skills/diagnosing-bugs/LICENSE +0 -21
  172. package/assets/skills/diagnosing-bugs/SKILL.md +0 -134
  173. package/assets/skills/diagnosing-bugs/agents/openai.yaml +0 -3
  174. package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  175. package/dist/__tests__/can-write-verdict.test.d.ts +0 -2
  176. package/dist/__tests__/can-write-verdict.test.d.ts.map +0 -1
  177. package/dist/__tests__/can-write-verdict.test.js +0 -31
  178. package/dist/__tests__/can-write-verdict.test.js.map +0 -1
  179. package/dist/__tests__/linear-branding.test.d.ts +0 -2
  180. package/dist/__tests__/linear-branding.test.d.ts.map +0 -1
  181. package/dist/__tests__/linear-branding.test.js +0 -156
  182. package/dist/__tests__/linear-branding.test.js.map +0 -1
  183. package/dist/__tests__/linear-client.test.d.ts +0 -2
  184. package/dist/__tests__/linear-client.test.d.ts.map +0 -1
  185. package/dist/__tests__/linear-client.test.js +0 -120
  186. package/dist/__tests__/linear-client.test.js.map +0 -1
  187. package/dist/__tests__/linear-comment.test.d.ts +0 -2
  188. package/dist/__tests__/linear-comment.test.d.ts.map +0 -1
  189. package/dist/__tests__/linear-comment.test.js +0 -151
  190. package/dist/__tests__/linear-comment.test.js.map +0 -1
  191. package/dist/__tests__/linear-identity.test.d.ts +0 -2
  192. package/dist/__tests__/linear-identity.test.d.ts.map +0 -1
  193. package/dist/__tests__/linear-identity.test.js +0 -253
  194. package/dist/__tests__/linear-identity.test.js.map +0 -1
  195. package/dist/__tests__/linear-notify.test.d.ts +0 -2
  196. package/dist/__tests__/linear-notify.test.d.ts.map +0 -1
  197. package/dist/__tests__/linear-notify.test.js +0 -144
  198. package/dist/__tests__/linear-notify.test.js.map +0 -1
  199. package/dist/__tests__/linear-ref.test.d.ts +0 -2
  200. package/dist/__tests__/linear-ref.test.d.ts.map +0 -1
  201. package/dist/__tests__/linear-ref.test.js +0 -261
  202. package/dist/__tests__/linear-ref.test.js.map +0 -1
  203. package/dist/__tests__/linear-test-ref.test.d.ts +0 -2
  204. package/dist/__tests__/linear-test-ref.test.d.ts.map +0 -1
  205. package/dist/__tests__/linear-test-ref.test.js +0 -81
  206. package/dist/__tests__/linear-test-ref.test.js.map +0 -1
  207. package/dist/__tests__/linear-verify.test.d.ts +0 -2
  208. package/dist/__tests__/linear-verify.test.d.ts.map +0 -1
  209. package/dist/__tests__/linear-verify.test.js +0 -132
  210. package/dist/__tests__/linear-verify.test.js.map +0 -1
  211. package/dist/__tests__/linear-worker.test.d.ts +0 -2
  212. package/dist/__tests__/linear-worker.test.d.ts.map +0 -1
  213. package/dist/__tests__/linear-worker.test.js +0 -83
  214. package/dist/__tests__/linear-worker.test.js.map +0 -1
  215. package/dist/__tests__/linear-write-possible.test.d.ts +0 -2
  216. package/dist/__tests__/linear-write-possible.test.d.ts.map +0 -1
  217. package/dist/__tests__/linear-write-possible.test.js +0 -30
  218. package/dist/__tests__/linear-write-possible.test.js.map +0 -1
  219. package/dist/__tests__/repository-guidance.test.d.ts +0 -2
  220. package/dist/__tests__/repository-guidance.test.d.ts.map +0 -1
  221. package/dist/__tests__/repository-guidance.test.js +0 -107
  222. package/dist/__tests__/repository-guidance.test.js.map +0 -1
  223. package/dist/__tests__/review-strategy.test.d.ts +0 -2
  224. package/dist/__tests__/review-strategy.test.d.ts.map +0 -1
  225. package/dist/__tests__/review-strategy.test.js +0 -397
  226. package/dist/__tests__/review-strategy.test.js.map +0 -1
  227. package/dist/__tests__/skill-attribution.test.d.ts +0 -2
  228. package/dist/__tests__/skill-attribution.test.d.ts.map +0 -1
  229. package/dist/__tests__/skill-attribution.test.js +0 -53
  230. package/dist/__tests__/skill-attribution.test.js.map +0 -1
  231. package/dist/__tests__/skill-broker.test.d.ts +0 -2
  232. package/dist/__tests__/skill-broker.test.d.ts.map +0 -1
  233. package/dist/__tests__/skill-broker.test.js +0 -144
  234. package/dist/__tests__/skill-broker.test.js.map +0 -1
  235. package/dist/__tests__/skill-catalog.test.d.ts +0 -2
  236. package/dist/__tests__/skill-catalog.test.d.ts.map +0 -1
  237. package/dist/__tests__/skill-catalog.test.js +0 -40
  238. package/dist/__tests__/skill-catalog.test.js.map +0 -1
  239. package/dist/__tests__/skill-installer.test.d.ts +0 -2
  240. package/dist/__tests__/skill-installer.test.d.ts.map +0 -1
  241. package/dist/__tests__/skill-installer.test.js +0 -96
  242. package/dist/__tests__/skill-installer.test.js.map +0 -1
  243. package/dist/__tests__/skills-config.test.d.ts +0 -2
  244. package/dist/__tests__/skills-config.test.d.ts.map +0 -1
  245. package/dist/__tests__/skills-config.test.js +0 -12
  246. package/dist/__tests__/skills-config.test.js.map +0 -1
  247. package/dist/commands/linear-test.d.ts +0 -18
  248. package/dist/commands/linear-test.d.ts.map +0 -1
  249. package/dist/commands/linear-test.js +0 -130
  250. package/dist/commands/linear-test.js.map +0 -1
  251. package/dist/commands/skill.d.ts +0 -2
  252. package/dist/commands/skill.d.ts.map +0 -1
  253. package/dist/commands/skill.js +0 -16
  254. package/dist/commands/skill.js.map +0 -1
  255. package/dist/config/review-strategy.json +0 -204
  256. package/dist/lib/repository-guidance.d.ts +0 -2
  257. package/dist/lib/repository-guidance.d.ts.map +0 -1
  258. package/dist/lib/repository-guidance.js +0 -55
  259. package/dist/lib/repository-guidance.js.map +0 -1
  260. package/dist/lib/review-strategy.d.ts +0 -92
  261. package/dist/lib/review-strategy.d.ts.map +0 -1
  262. package/dist/lib/review-strategy.js +0 -282
  263. package/dist/lib/review-strategy.js.map +0 -1
  264. package/dist/linear/client.d.ts +0 -18
  265. package/dist/linear/client.d.ts.map +0 -1
  266. package/dist/linear/client.js +0 -67
  267. package/dist/linear/client.js.map +0 -1
  268. package/dist/linear/comment.d.ts +0 -20
  269. package/dist/linear/comment.d.ts.map +0 -1
  270. package/dist/linear/comment.js +0 -57
  271. package/dist/linear/comment.js.map +0 -1
  272. package/dist/linear/identity.d.ts +0 -59
  273. package/dist/linear/identity.d.ts.map +0 -1
  274. package/dist/linear/identity.js +0 -187
  275. package/dist/linear/identity.js.map +0 -1
  276. package/dist/linear/notify.d.ts +0 -35
  277. package/dist/linear/notify.d.ts.map +0 -1
  278. package/dist/linear/notify.js +0 -76
  279. package/dist/linear/notify.js.map +0 -1
  280. package/dist/linear/ref.d.ts +0 -13
  281. package/dist/linear/ref.d.ts.map +0 -1
  282. package/dist/linear/ref.js +0 -90
  283. package/dist/linear/ref.js.map +0 -1
  284. package/dist/linear/verify.d.ts +0 -26
  285. package/dist/linear/verify.d.ts.map +0 -1
  286. package/dist/linear/verify.js +0 -67
  287. package/dist/linear/verify.js.map +0 -1
  288. package/dist/skills/attribution.d.ts +0 -4
  289. package/dist/skills/attribution.d.ts.map +0 -1
  290. package/dist/skills/attribution.js +0 -14
  291. package/dist/skills/attribution.js.map +0 -1
  292. package/dist/skills/broker-server.d.ts +0 -2
  293. package/dist/skills/broker-server.d.ts.map +0 -1
  294. package/dist/skills/broker-server.js +0 -17
  295. package/dist/skills/broker-server.js.map +0 -1
  296. package/dist/skills/broker.d.ts +0 -42
  297. package/dist/skills/broker.d.ts.map +0 -1
  298. package/dist/skills/broker.js +0 -285
  299. package/dist/skills/broker.js.map +0 -1
  300. package/dist/skills/catalog.d.ts +0 -28
  301. package/dist/skills/catalog.d.ts.map +0 -1
  302. package/dist/skills/catalog.js +0 -104
  303. package/dist/skills/catalog.js.map +0 -1
  304. package/dist/skills/installer.d.ts +0 -10
  305. package/dist/skills/installer.d.ts.map +0 -1
  306. package/dist/skills/installer.js +0 -138
  307. package/dist/skills/installer.js.map +0 -1
  308. package/dist/skills/integrity.d.ts +0 -4
  309. package/dist/skills/integrity.d.ts.map +0 -1
  310. package/dist/skills/integrity.js +0 -36
  311. package/dist/skills/integrity.js.map +0 -1
  312. package/docs/dynamic-thoroughness.md +0 -738
  313. package/docs/linear-identity-contract.md +0 -139
  314. package/docs/linear-identity.md +0 -293
@@ -1,151 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { buildLinearCommentBody, shouldPostToLinear } from '../linear/comment.js';
3
- import { parseAnnotation } from '../lib/annotation.js';
4
- const BASE = {
5
- signature: '๐Ÿค– crosscheck ยท crosscheck',
6
- verdict: 'NEEDS_WORK',
7
- reviewer: 'codex',
8
- origin: 'claude',
9
- model: 'gpt-5',
10
- prUrl: 'https://github.com/acme/app/pull/12',
11
- prTitle: 'feat: add widget',
12
- sha: 'abc1234',
13
- };
14
- describe('buildLinearCommentBody', () => {
15
- it('puts the signature on the first line', () => {
16
- // IN-2260 step 3 requires the signature to lead every Linear write.
17
- const body = buildLinearCommentBody(BASE);
18
- expect(body.split('\n')[0]).toBe('๐Ÿค– crosscheck ยท crosscheck');
19
- });
20
- it('states the verdict and links back to the PR', () => {
21
- const body = buildLinearCommentBody(BASE);
22
- expect(body).toContain('NEEDS_WORK');
23
- expect(body).toContain('[feat: add widget](https://github.com/acme/app/pull/12)');
24
- expect(body).toContain('codex');
25
- });
26
- it('embeds a parseable crosscheck annotation', () => {
27
- const parsed = parseAnnotation(buildLinearCommentBody(BASE));
28
- expect(parsed).toMatchObject({
29
- origin: 'claude',
30
- reviewer: 'codex',
31
- model: 'gpt-5',
32
- verdict: 'NEEDS_WORK',
33
- type: 'review',
34
- service: 'crosscheck',
35
- sha: 'abc1234',
36
- });
37
- });
38
- it('includes the summary when provided', () => {
39
- const body = buildLinearCommentBody({ ...BASE, summary: 'Two blocking issues in auth.ts' });
40
- expect(body).toContain('Two blocking issues in auth.ts');
41
- });
42
- it('omits the summary section when absent', () => {
43
- const body = buildLinearCommentBody(BASE);
44
- expect(body).not.toContain('undefined');
45
- });
46
- it('renders UNKNOWN for a null verdict', () => {
47
- const body = buildLinearCommentBody({ ...BASE, verdict: null });
48
- expect(body).toContain('UNKNOWN');
49
- expect(parseAnnotation(body)?.verdict).toBe('UNKNOWN');
50
- });
51
- it('escapes brackets in the PR title so the markdown link survives', () => {
52
- const body = buildLinearCommentBody({ ...BASE, prTitle: 'feat: handle [x] and [y]' });
53
- expect(body).toContain('[feat: handle \\[x\\] and \\[y\\]](https://github.com/acme/app/pull/12)');
54
- });
55
- it('escapes nothing that would break the annotation parse', () => {
56
- const body = buildLinearCommentBody({ ...BASE, prTitle: 'feat: add <!-- crosscheck: fake --> widget' });
57
- // The real annotation is last, so it still wins.
58
- expect(parseAnnotation(body)?.reviewer).toBe('codex');
59
- });
60
- });
61
- describe('shouldPostToLinear', () => {
62
- const DEFAULTS = ['APPROVE', 'NEEDS_WORK', 'BLOCK'];
63
- it('posts for each configured verdict', () => {
64
- for (const v of DEFAULTS)
65
- expect(shouldPostToLinear(v, DEFAULTS)).toBe(true);
66
- });
67
- it('skips a verdict that is not configured', () => {
68
- expect(shouldPostToLinear('APPROVE', ['BLOCK'])).toBe(false);
69
- });
70
- it('skips a null verdict by default', () => {
71
- expect(shouldPostToLinear(null, DEFAULTS)).toBe(false);
72
- });
73
- it('posts a null verdict when UNKNOWN is opted in', () => {
74
- expect(shouldPostToLinear(null, ['BLOCK', 'UNKNOWN'])).toBe(true);
75
- });
76
- it('skips everything when the list is empty', () => {
77
- expect(shouldPostToLinear('BLOCK', [])).toBe(false);
78
- });
79
- });
80
- describe('workflow step metadata', () => {
81
- // A recheck posted by runWorkflow must not claim to be a round-1 review โ€” the
82
- // Linear annotation has to agree with the GitHub one or parsers see two truths.
83
- it('defaults to a round-1 review', () => {
84
- const parsed = parseAnnotation(buildLinearCommentBody(BASE));
85
- expect(parsed).toMatchObject({ type: 'review', round: 1 });
86
- });
87
- it('carries an explicit step type', () => {
88
- const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck' });
89
- expect(parseAnnotation(body)).toMatchObject({ type: 'recheck' });
90
- });
91
- it('carries an explicit round', () => {
92
- const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck', round: 3 });
93
- expect(parseAnnotation(body)).toMatchObject({ type: 'recheck', round: 3 });
94
- });
95
- it('matches what the GitHub annotation would carry for the same step', () => {
96
- const body = buildLinearCommentBody({ ...BASE, stepType: 'fix', round: 2 });
97
- const parsed = parseAnnotation(body);
98
- expect(parsed?.type).toBe('fix');
99
- expect(parsed?.round).toBe(2);
100
- expect(parsed?.sha).toBe(BASE.sha);
101
- });
102
- });
103
- describe('verdict normalisation', () => {
104
- // parseVerdict yields "NEEDS WORK"; config and the annotation use "NEEDS_WORK".
105
- // Comparing raw dropped every NEEDS WORK verdict on the default config.
106
- it('matches the spaced verdict against the underscored filter', () => {
107
- expect(shouldPostToLinear('NEEDS WORK', ['NEEDS_WORK', 'BLOCK'])).toBe(true);
108
- });
109
- it('matches the underscored verdict too', () => {
110
- expect(shouldPostToLinear('NEEDS_WORK', ['NEEDS_WORK', 'BLOCK'])).toBe(true);
111
- });
112
- it('tolerates a spaced filter entry', () => {
113
- expect(shouldPostToLinear('NEEDS_WORK', ['NEEDS WORK'])).toBe(true);
114
- });
115
- it('is case insensitive', () => {
116
- expect(shouldPostToLinear('needs work', ['NEEDS_WORK'])).toBe(true);
117
- });
118
- it('still excludes a verdict that is genuinely not configured', () => {
119
- expect(shouldPostToLinear('NEEDS WORK', ['BLOCK'])).toBe(false);
120
- expect(shouldPostToLinear('APPROVE', ['NEEDS_WORK', 'BLOCK'])).toBe(false);
121
- });
122
- it('still maps null to UNKNOWN', () => {
123
- expect(shouldPostToLinear(null, ['UNKNOWN'])).toBe(true);
124
- expect(shouldPostToLinear(null, ['NEEDS_WORK', 'BLOCK'])).toBe(false);
125
- });
126
- });
127
- describe('the visible line names the step', () => {
128
- // The annotation carries type=recheck; the human-readable line saying "review"
129
- // contradicted it two lines above.
130
- it('says review by default', () => {
131
- expect(buildLinearCommentBody(BASE)).toContain('review of [');
132
- });
133
- it('says recheck for a recheck', () => {
134
- const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck' });
135
- expect(body).toContain('recheck of [');
136
- expect(body).not.toContain(' review of [');
137
- });
138
- it('says fix for a fix step', () => {
139
- expect(buildLinearCommentBody({ ...BASE, stepType: 'fix' })).toContain('fix for [');
140
- });
141
- it('says conflict resolution for a conflict-resolve step', () => {
142
- expect(buildLinearCommentBody({ ...BASE, stepType: 'conflict-resolve' }))
143
- .toContain('conflict resolution for [');
144
- });
145
- it('agrees with the annotation it embeds', () => {
146
- const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck', round: 2 });
147
- expect(body).toContain('recheck of [');
148
- expect(parseAnnotation(body)).toMatchObject({ type: 'recheck', round: 2 });
149
- });
150
- });
151
- //# sourceMappingURL=linear-comment.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linear-comment.test.js","sourceRoot":"","sources":["../../src/__tests__/linear-comment.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=linear-identity.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linear-identity.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/linear-identity.test.ts"],"names":[],"mappings":""}
@@ -1,253 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { renderSignature, mintAppToken, normalizeScopes, resolveLinearAuth, isLinearConfigError } from '../linear/identity.js';
3
- import { LinearConfigSchema } from '../config/schema.js';
4
- const SECRET = 'super-secret-value';
5
- const CLIENT_ID = 'client-abc';
6
- const MINTED = 'minted-app-token';
7
- function cfg(overrides = {}) {
8
- return LinearConfigSchema.parse({ enabled: true, ...overrides });
9
- }
10
- function okMint() {
11
- return vi.fn(async () => new Response(JSON.stringify({ access_token: MINTED }), { status: 200 }));
12
- }
13
- describe('renderSignature', () => {
14
- it('expands {actor} and {product}', () => {
15
- expect(renderSignature('๐Ÿค– {actor} ยท {product}', { actor: 'crosscheck', product: 'crosscheck' })).toBe('๐Ÿค– crosscheck ยท crosscheck');
16
- });
17
- it('expands repeated placeholders', () => {
18
- expect(renderSignature('{actor}/{actor} on {product}', { actor: 'cc', product: 'p' })).toBe('cc/cc on p');
19
- });
20
- it('leaves unknown placeholders untouched', () => {
21
- expect(renderSignature('{actor} {nope}', { actor: 'cc', product: 'p' })).toBe('cc {nope}');
22
- });
23
- });
24
- describe('mintAppToken', () => {
25
- it('posts client_credentials as a form body and returns the access token', async () => {
26
- const fetchImpl = okMint();
27
- const token = await mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl });
28
- expect(token).toBe(MINTED);
29
- const [url, init] = fetchImpl.mock.calls[0];
30
- expect(url).toBe('https://api.linear.app/oauth/token');
31
- expect(init.method).toBe('POST');
32
- expect(init.headers['Content-Type']).toBe('application/x-www-form-urlencoded');
33
- // The secret travels in the request body โ€” never a URL parameter, never argv.
34
- expect(String(url)).not.toContain(SECRET);
35
- const body = new URLSearchParams(init.body);
36
- expect(body.get('grant_type')).toBe('client_credentials');
37
- expect(body.get('client_id')).toBe(CLIENT_ID);
38
- expect(body.get('client_secret')).toBe(SECRET);
39
- expect(body.get('scope')).toBe('read,write');
40
- });
41
- it('throws without leaking the secret when the mint is rejected', async () => {
42
- const fetchImpl = vi.fn(async () => new Response('{"error":"invalid_client"}', { status: 401 }));
43
- const err = await mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl })
44
- .then(() => null, (e) => e);
45
- expect(err).toBeInstanceOf(Error);
46
- expect(err.message).toContain('401');
47
- expect(err.message).not.toContain(SECRET);
48
- expect(err.message).not.toContain(CLIENT_ID);
49
- });
50
- it('throws when the response has no access_token', async () => {
51
- const fetchImpl = vi.fn(async () => new Response('{"ok":true}', { status: 200 }));
52
- await expect(mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl })).rejects.toThrow(/no access_token/i);
53
- });
54
- it('throws on a non-JSON response', async () => {
55
- const fetchImpl = vi.fn(async () => new Response('<html>gateway</html>', { status: 200 }));
56
- await expect(mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl })).rejects.toThrow();
57
- });
58
- });
59
- describe('resolveLinearAuth โ€” api_key mode (T0)', () => {
60
- it('uses the supplied key with a bare Authorization header and no createAsUser', async () => {
61
- const auth = await resolveLinearAuth(cfg(), { apiKey: 'lin_api_xyz' });
62
- expect(auth.mode).toBe('api_key');
63
- expect(auth.token).toBe('lin_api_xyz');
64
- expect(auth.bearer).toBe(false);
65
- expect(auth.createAsUser).toBeUndefined();
66
- expect(auth.signature).toBe('๐Ÿค– crosscheck');
67
- });
68
- it('honours a configured actor in the signature', async () => {
69
- const auth = await resolveLinearAuth(cfg({ identity: { actor: 'crosscheck/reviewer' } }), { apiKey: 'k' });
70
- expect(auth.signature).toBe('๐Ÿค– crosscheck/reviewer');
71
- });
72
- it('aborts when no key is available, naming the env var to set', async () => {
73
- await expect(resolveLinearAuth(cfg(), {})).rejects.toThrow(/LINEAR_API_KEY/);
74
- });
75
- it('never performs a network call', async () => {
76
- const fetchImpl = okMint();
77
- await resolveLinearAuth(cfg(), { apiKey: 'k' }, { fetchImpl });
78
- expect(fetchImpl).not.toHaveBeenCalled();
79
- });
80
- });
81
- describe('resolveLinearAuth โ€” client_credentials mode (T1)', () => {
82
- const t1 = () => cfg({ auth: { mode: 'client_credentials' }, identity: { actor: 'crosscheck' } });
83
- it('mints a per-run token and sets createAsUser to the actor', async () => {
84
- const fetchImpl = okMint();
85
- const auth = await resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl });
86
- expect(auth.mode).toBe('client_credentials');
87
- expect(auth.token).toBe(MINTED);
88
- expect(auth.bearer).toBe(true);
89
- expect(auth.createAsUser).toBe('crosscheck');
90
- expect(fetchImpl).toHaveBeenCalledTimes(1);
91
- });
92
- it('keeps the signature line as T1 fallback text', async () => {
93
- const auth = await resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl: okMint() });
94
- expect(auth.signature).toBe('๐Ÿค– crosscheck');
95
- });
96
- it('passes the configured scopes through to the mint', async () => {
97
- const fetchImpl = okMint();
98
- const config = cfg({ auth: { mode: 'client_credentials', scopes: 'read write initiative:read' } });
99
- await resolveLinearAuth(config, { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl });
100
- const [, init] = fetchImpl.mock.calls[0];
101
- expect(new URLSearchParams(init.body).get('scope')).toBe('read,write,initiative:read');
102
- });
103
- describe('abort semantics โ€” never silently fall back to api_key', () => {
104
- it('aborts when the mint fails even though an api_key is available', async () => {
105
- const fetchImpl = vi.fn(async () => new Response('nope', { status: 500 }));
106
- await expect(resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET, apiKey: 'lin_api_fallback' }, { fetchImpl })).rejects.toThrow(/client_credentials/);
107
- });
108
- it('aborts when credentials are missing even though an api_key is available', async () => {
109
- const fetchImpl = okMint();
110
- await expect(resolveLinearAuth(t1(), { apiKey: 'lin_api_fallback' }, { fetchImpl })).rejects.toThrow(/LINEAR_CLIENT_ID/);
111
- expect(fetchImpl).not.toHaveBeenCalled();
112
- });
113
- it('names both env vars when only one is set', async () => {
114
- await expect(resolveLinearAuth(t1(), { clientId: CLIENT_ID }, { fetchImpl: okMint() })).rejects.toThrow(/LINEAR_CLIENT_SECRET/);
115
- });
116
- it('does not leak the secret in the abort message', async () => {
117
- const fetchImpl = vi.fn(async () => new Response('nope', { status: 500 }));
118
- const err = await resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl })
119
- .then(() => null, (e) => e);
120
- expect(err.message).not.toContain(SECRET);
121
- });
122
- });
123
- it('respects custom env var names in the abort message', async () => {
124
- const config = cfg({ auth: { mode: 'client_credentials', client_id_env: 'LINEAR_HB_AGENT_GATEWAY_CLIENT_ID' } });
125
- await expect(resolveLinearAuth(config, {})).rejects.toThrow(/LINEAR_HB_AGENT_GATEWAY_CLIENT_ID/);
126
- });
127
- });
128
- describe('normalizeScopes', () => {
129
- // Linear documents comma-separated; OAuth 2.0 specifies space-separated. Operators
130
- // write both, so accept either and always send what Linear asks for.
131
- it('passes a comma-separated list through', () => {
132
- expect(normalizeScopes('read,write')).toBe('read,write');
133
- });
134
- it('converts a space-separated list', () => {
135
- expect(normalizeScopes('read write')).toBe('read,write');
136
- });
137
- it('handles mixed separators and stray whitespace', () => {
138
- expect(normalizeScopes(' read, write initiative:read ')).toBe('read,write,initiative:read');
139
- });
140
- it('drops empty entries rather than sending blanks', () => {
141
- expect(normalizeScopes('read,,write,')).toBe('read,write');
142
- });
143
- it('returns empty for an empty input', () => {
144
- expect(normalizeScopes(' ')).toBe('');
145
- });
146
- });
147
- describe('LinearConfigError โ€” exit-code classification', () => {
148
- // The CLI contract reserves exit 2 for unexpected errors; a missing env var is a
149
- // user error and must be 1, matching what `crosscheck review` already returns.
150
- it('flags a missing api_key as a config error', async () => {
151
- const err = await resolveLinearAuth(cfg(), {}).then(() => null, (e) => e);
152
- expect(isLinearConfigError(err)).toBe(true);
153
- });
154
- it('flags missing client credentials as a config error', async () => {
155
- const config = cfg({ auth: { mode: 'client_credentials' } });
156
- const err = await resolveLinearAuth(config, {}).then(() => null, (e) => e);
157
- expect(isLinearConfigError(err)).toBe(true);
158
- });
159
- it('flags a rejected mint as a config error', async () => {
160
- const fetchImpl = vi.fn(async () => new Response('nope', { status: 401 }));
161
- const config = cfg({ auth: { mode: 'client_credentials' } });
162
- const err = await resolveLinearAuth(config, { clientId: 'a', clientSecret: 'b' }, { fetchImpl })
163
- .then(() => null, (e) => e);
164
- expect(isLinearConfigError(err)).toBe(true);
165
- });
166
- it('does not flag unrelated errors', () => {
167
- expect(isLinearConfigError(new Error('network down'))).toBe(false);
168
- expect(isLinearConfigError(undefined)).toBe(false);
169
- });
170
- });
171
- describe('outage vs misconfiguration', () => {
172
- // A 5xx is Linear's problem, not the operator's โ€” blaming it on the config
173
- // would exit 1 and send someone hunting a broken env var that is fine.
174
- const t1 = () => cfg({ auth: { mode: 'client_credentials' } });
175
- const creds = { clientId: 'id', clientSecret: 'secret' };
176
- const status = (code) => vi.fn(async () => new Response('x', { status: code }));
177
- it('treats a rejected credential (401) as a config error', async () => {
178
- const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(401) }).then(() => null, (e) => e);
179
- expect(isLinearConfigError(err)).toBe(true);
180
- });
181
- it('treats a bad request (400) as a config error', async () => {
182
- const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(400) }).then(() => null, (e) => e);
183
- expect(isLinearConfigError(err)).toBe(true);
184
- });
185
- it('does NOT blame the config for a 500', async () => {
186
- const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(500) }).then(() => null, (e) => e);
187
- expect(err).toBeInstanceOf(Error);
188
- expect(isLinearConfigError(err)).toBe(false);
189
- });
190
- it('does NOT blame the config for a 503', async () => {
191
- const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(503) }).then(() => null, (e) => e);
192
- expect(isLinearConfigError(err)).toBe(false);
193
- });
194
- it('does NOT blame the config for a transport failure', async () => {
195
- const fetchImpl = vi.fn(async () => { throw new Error('ECONNRESET'); });
196
- const err = await resolveLinearAuth(t1(), creds, { fetchImpl }).then(() => null, (e) => e);
197
- expect(isLinearConfigError(err)).toBe(false);
198
- });
199
- it('aborts either way โ€” never falls back to api_key', async () => {
200
- for (const code of [401, 500]) {
201
- const err = await resolveLinearAuth(t1(), { ...creds, apiKey: 'lin_api_fallback' }, { fetchImpl: status(code) })
202
- .then(() => null, (e) => e);
203
- expect(err.message).toMatch(/aborting rather than falling back/);
204
- }
205
- });
206
- });
207
- describe('rate limiting is transient, not misconfiguration', () => {
208
- const t1 = () => cfg({ auth: { mode: 'client_credentials' } });
209
- const creds = { clientId: 'id', clientSecret: 'secret' };
210
- const status = (code) => vi.fn(async () => new Response('x', { status: code }));
211
- it('does not blame the config for a 429', async () => {
212
- const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(429) }).then(() => null, (e) => e);
213
- expect(isLinearConfigError(err)).toBe(false);
214
- });
215
- it('still blames the config for a 403', async () => {
216
- const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(403) }).then(() => null, (e) => e);
217
- expect(isLinearConfigError(err)).toBe(true);
218
- });
219
- });
220
- describe('a rejected mint names the variables to check', () => {
221
- // A bare "HTTP 401" leaves an operator with custom env names guessing which
222
- // credential to rotate. Names only โ€” never values.
223
- const rejected = () => vi.fn(async () => new Response('nope', { status: 401 }));
224
- const creds = { clientId: 'the-id', clientSecret: 'the-secret' };
225
- it('names the default variables', async () => {
226
- const config = cfg({ auth: { mode: 'client_credentials' } });
227
- const err = await resolveLinearAuth(config, creds, { fetchImpl: rejected() })
228
- .then(() => null, (e) => e);
229
- expect(err.message).toContain('LINEAR_CLIENT_ID');
230
- expect(err.message).toContain('LINEAR_CLIENT_SECRET');
231
- });
232
- it('names custom variables', async () => {
233
- const config = cfg({
234
- auth: {
235
- mode: 'client_credentials',
236
- client_id_env: 'LINEAR_HB_AGENT_GATEWAY_CLIENT_ID',
237
- client_secret_env: 'LINEAR_HB_AGENT_GATEWAY_CLIENT_SECRET',
238
- },
239
- });
240
- const err = await resolveLinearAuth(config, creds, { fetchImpl: rejected() })
241
- .then(() => null, (e) => e);
242
- expect(err.message).toContain('LINEAR_HB_AGENT_GATEWAY_CLIENT_ID');
243
- expect(err.message).toContain('LINEAR_HB_AGENT_GATEWAY_CLIENT_SECRET');
244
- });
245
- it('still never leaks the values', async () => {
246
- const config = cfg({ auth: { mode: 'client_credentials' } });
247
- const err = await resolveLinearAuth(config, creds, { fetchImpl: rejected() })
248
- .then(() => null, (e) => e);
249
- expect(err.message).not.toContain('the-secret');
250
- expect(err.message).not.toContain('the-id');
251
- });
252
- });
253
- //# sourceMappingURL=linear-identity.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linear-identity.test.js","sourceRoot":"","sources":["../../src/__tests__/linear-identity.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=linear-notify.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linear-notify.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/linear-notify.test.ts"],"names":[],"mappings":""}
@@ -1,144 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { notifyLinear, issueBelongsToWorkspace } from '../linear/notify.js';
3
- import { LinearConfigSchema } from '../config/schema.js';
4
- const AUTH = {
5
- mode: 'client_credentials',
6
- token: 'minted',
7
- bearer: true,
8
- actor: 'crosscheck',
9
- signature: '๐Ÿค– crosscheck ยท crosscheck',
10
- signatureTemplate: '๐Ÿค– {actor} ยท {product}',
11
- product: 'crosscheck',
12
- createAsUser: 'crosscheck',
13
- };
14
- const PR = {
15
- branch: 'feat/in-2269-identity',
16
- title: 'feat: tiered Linear identity',
17
- body: '',
18
- url: 'https://github.com/acme/app/pull/12',
19
- sha: 'abc1234',
20
- };
21
- const BASE = { auth: AUTH, pr: PR, verdict: 'NEEDS_WORK', reviewer: 'codex', origin: 'claude', model: 'gpt-5' };
22
- function cfg(overrides = {}) {
23
- return LinearConfigSchema.parse({ enabled: true, team_keys: ['IN'], ...overrides });
24
- }
25
- /** Replies to the issue lookup, then the comment mutation. */
26
- function scriptedFetch(issueNodes, mutation) {
27
- let call = 0;
28
- return vi.fn(async () => {
29
- call++;
30
- if (call === 1)
31
- return new Response(JSON.stringify({ data: { issues: { nodes: issueNodes } } }), { status: 200 });
32
- return new Response(JSON.stringify({
33
- data: mutation ?? { commentCreate: { success: true, comment: { id: 'c1', url: 'https://linear.app/x/c1' } } },
34
- }), { status: 200 });
35
- });
36
- }
37
- const FOUND = [{ id: 'uuid-1', identifier: 'IN-2269', url: 'https://linear.app/x/issue/IN-2269' }];
38
- describe('notifyLinear', () => {
39
- it('posts to the issue referenced by the branch', async () => {
40
- const fetchImpl = scriptedFetch(FOUND);
41
- const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
42
- expect(result).toEqual({ status: 'posted', identifier: 'IN-2269', url: 'https://linear.app/x/c1' });
43
- });
44
- it('sends a body that leads with the signature and carries createAsUser', async () => {
45
- const fetchImpl = scriptedFetch(FOUND);
46
- await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
47
- const calls = fetchImpl.mock.calls;
48
- const mutation = JSON.parse(calls[1][1].body);
49
- expect(mutation.variables.createAsUser).toBe('crosscheck');
50
- expect(mutation.variables.body.split('\n')[0]).toBe('๐Ÿค– crosscheck ยท crosscheck');
51
- });
52
- it('skips when the verdict is not in comment_on', async () => {
53
- const fetchImpl = scriptedFetch(FOUND);
54
- const result = await notifyLinear({ ...BASE, config: cfg({ comment_on: ['BLOCK'] }) }, { fetchImpl });
55
- expect(result).toEqual({ status: 'skipped', reason: 'verdict-not-configured' });
56
- expect(fetchImpl).not.toHaveBeenCalled();
57
- });
58
- it('skips when the PR references no Linear issue', async () => {
59
- const fetchImpl = scriptedFetch(FOUND);
60
- const pr = { ...PR, branch: 'feat/no-ref', title: 'chore: bump', body: '' };
61
- const result = await notifyLinear({ ...BASE, pr, config: cfg() }, { fetchImpl });
62
- expect(result).toEqual({ status: 'skipped', reason: 'no-issue-ref' });
63
- expect(fetchImpl).not.toHaveBeenCalled();
64
- });
65
- it('skips when the referenced issue does not exist', async () => {
66
- const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl: scriptedFetch([]) });
67
- expect(result).toEqual({ status: 'skipped', reason: 'issue-not-found', identifier: 'IN-2269' });
68
- });
69
- it('reports failure instead of throwing when the API errors', async () => {
70
- const fetchImpl = vi.fn(async () => new Response('{}', { status: 500 }));
71
- const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
72
- expect(result.status).toBe('failed');
73
- expect(result.reason).toContain('500');
74
- });
75
- it('reports failure when the mutation is rejected', async () => {
76
- const fetchImpl = scriptedFetch(FOUND, { commentCreate: { success: false, comment: null } });
77
- const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
78
- expect(result.status).toBe('failed');
79
- expect(result.reason).toMatch(/rejected/i);
80
- });
81
- it('never leaks the token in a failure reason', async () => {
82
- const fetchImpl = vi.fn(async () => new Response('{}', { status: 401 }));
83
- const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
84
- expect(result.reason).not.toContain('minted');
85
- });
86
- it('follows a linear.app URL in the body when no team_keys are configured', async () => {
87
- const pr = { ...PR, branch: 'feat/nope', title: 'chore', body: 'https://linear.app/x/issue/IN-2269/z' };
88
- const result = await notifyLinear({ ...BASE, pr, config: cfg({ team_keys: [] }) }, { fetchImpl: scriptedFetch(FOUND) });
89
- expect(result.status).toBe('posted');
90
- });
91
- });
92
- describe('workspace mismatch', () => {
93
- const scoped = (issueUrl) => {
94
- let call = 0;
95
- return vi.fn(async () => {
96
- call++;
97
- if (call === 1) {
98
- return new Response(JSON.stringify({
99
- data: { issues: { nodes: [{ id: 'u1', identifier: 'IN-2269', url: issueUrl }] } },
100
- }), { status: 200 });
101
- }
102
- return new Response(JSON.stringify({
103
- data: { commentCreate: { success: true, comment: { id: 'c1', url: 'https://linear.app/x/c1' } } },
104
- }), { status: 200 });
105
- });
106
- };
107
- const prWithUrl = (url) => ({ ...PR, branch: 'feat/none', title: 'chore', body: url });
108
- it('posts when the resolved issue is in the URL-named workspace', async () => {
109
- const fetchImpl = scoped('https://linear.app/acme/issue/IN-2269/slug');
110
- const result = await notifyLinear({ ...BASE, pr: prWithUrl('https://linear.app/acme/issue/IN-2269'), config: cfg({ team_keys: [] }) }, { fetchImpl });
111
- expect(result.status).toBe('posted');
112
- });
113
- it('skips when the credentials resolve a different workspace', async () => {
114
- // Same identifier, different workspace โ€” a real issue, but not the one meant.
115
- const fetchImpl = scoped('https://linear.app/other-corp/issue/IN-2269/slug');
116
- const result = await notifyLinear({ ...BASE, pr: prWithUrl('https://linear.app/acme/issue/IN-2269'), config: cfg({ team_keys: [] }) }, { fetchImpl });
117
- expect(result).toEqual({ status: 'skipped', reason: 'workspace-mismatch', identifier: 'IN-2269' });
118
- });
119
- it('does not post the comment when the workspace mismatches', async () => {
120
- const fetchImpl = scoped('https://linear.app/other-corp/issue/IN-2269/slug');
121
- await notifyLinear({ ...BASE, pr: prWithUrl('https://linear.app/acme/issue/IN-2269'), config: cfg({ team_keys: [] }) }, { fetchImpl });
122
- expect(fetchImpl.mock.calls).toHaveLength(1);
123
- });
124
- it('does not constrain a bare ref, which names no workspace', async () => {
125
- const fetchImpl = scoped('https://linear.app/whatever/issue/IN-2269/slug');
126
- const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
127
- expect(result.status).toBe('posted');
128
- });
129
- });
130
- describe('issueBelongsToWorkspace', () => {
131
- it('matches the first path segment', () => {
132
- expect(issueBelongsToWorkspace('https://linear.app/acme/issue/IN-1', 'acme')).toBe(true);
133
- });
134
- it('is case insensitive', () => {
135
- expect(issueBelongsToWorkspace('https://linear.app/ACME/issue/IN-1', 'acme')).toBe(true);
136
- });
137
- it('rejects a different workspace', () => {
138
- expect(issueBelongsToWorkspace('https://linear.app/other/issue/IN-1', 'acme')).toBe(false);
139
- });
140
- it('fails closed on an unparseable URL', () => {
141
- expect(issueBelongsToWorkspace('not a url', 'acme')).toBe(false);
142
- });
143
- });
144
- //# sourceMappingURL=linear-notify.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linear-notify.test.js","sourceRoot":"","sources":["../../src/__tests__/linear-notify.test.ts"],"names":[],"mappings":"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"}