@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,187 +0,0 @@
1
- // Tiered Linear identity (IN-2267 / IN-2269).
2
- //
3
- // T0 api_key — operator supplies a personal/workspace key. Writes carry a
4
- // `🤖 {actor} · {product}` signature line. Works everywhere,
5
- // weakest attribution.
6
- // T1 client_credentials — operator creates an OAuth app in their own workspace and
7
- // enables the Client credentials toggle. We mint a Bearer app
8
- // token per run and pass `createAsUser` on every write, so
9
- // Linear renders them as the app (botActor), not a human.
10
- //
11
- // Hard requirements this module enforces:
12
- // * Secrets travel in a POST body — never on argv, never in a URL, never logged.
13
- // * A configured-but-failing T1 mint ABORTS. It must never silently downgrade to
14
- // api_key, because that would re-attribute agent writes to a human account.
15
- const TOKEN_ENDPOINT = 'https://api.linear.app/oauth/token';
16
- const DEFAULT_PRODUCT = 'crosscheck';
17
- // Misconfiguration (missing env var, rejected credentials) is a user error, so it
18
- // must surface as exit 1 — the CLI contract reserves 2 for unexpected failures.
19
- // commands/review.ts already exits 1 here; the workflow path has to agree.
20
- export class LinearConfigError extends Error {
21
- userError = true;
22
- constructor(message) {
23
- super(message);
24
- this.name = 'LinearConfigError';
25
- }
26
- }
27
- export function isLinearConfigError(err) {
28
- return err instanceof LinearConfigError;
29
- }
30
- // Renders the signature template. Unknown placeholders are left alone; known ones
31
- // with no value resolve to empty, and the leftover punctuation is tidied so a
32
- // template like `🤖 {icon} {actor} · {product} · {model}` still reads correctly
33
- // when icon and model are unset.
34
- export function renderSignature(template, vars) {
35
- const values = {
36
- actor: vars.actor,
37
- product: vars.product,
38
- model: vars.model ?? '',
39
- reviewer: vars.reviewer ?? '',
40
- icon: vars.icon ?? '',
41
- };
42
- // Mark where an empty placeholder stood so tidying can target exactly those gaps
43
- // and leave separators the operator wrote deliberately alone.
44
- const HOLE = '\u0000';
45
- const substituted = template.replace(/\{(actor|product|model|reviewer|icon)\}/g, (_match, key) => values[key] === '' ? HOLE : values[key]);
46
- return tidyHoles(substituted, HOLE);
47
- }
48
- // Removes each empty-placeholder hole together with ONE adjacent separator, so
49
- // `{a} · {model} · {b}` with no model yields `a · b` rather than `a · · b`.
50
- // Separators the operator wrote between two present values are never touched.
51
- function tidyHoles(text, hole) {
52
- const SEP = '(?:\\s*[·—|]\\s*|\\s+)';
53
- return text
54
- // hole with a separator on either side — drop the hole and one separator
55
- .replace(new RegExp(`${SEP}${hole}(?=${SEP})`, 'g'), '')
56
- // hole at the end of the string, with its leading separator
57
- .replace(new RegExp(`${SEP}${hole}\\s*$`, 'g'), '')
58
- // hole at the start, with its trailing separator
59
- .replace(new RegExp(`^\\s*${hole}${SEP}`, 'g'), '')
60
- // any hole left over (no adjacent separator)
61
- .split(hole).join('')
62
- .trim();
63
- }
64
- /** Wraps a configured icon URL as inline markdown, or '' when unset. */
65
- export function renderIcon(iconUrl) {
66
- const trimmed = iconUrl.trim();
67
- return trimmed ? `![](${trimmed})` : '';
68
- }
69
- // Linear's token endpoint documents scope as a COMMA-separated list, but OAuth 2.0
70
- // itself specifies space-separated, so operators write it both ways. Accept either
71
- // and always send commas.
72
- export function normalizeScopes(scopes) {
73
- return scopes.split(/[\s,]+/).filter(Boolean).join(',');
74
- }
75
- export async function mintAppToken(creds, opts = {}) {
76
- const doFetch = opts.fetchImpl ?? globalThis.fetch;
77
- // URLSearchParams keeps the secret in the request body. Nothing here reaches argv.
78
- const body = new URLSearchParams({
79
- grant_type: 'client_credentials',
80
- client_id: creds.clientId,
81
- client_secret: creds.clientSecret,
82
- scope: normalizeScopes(creds.scopes),
83
- });
84
- let response;
85
- try {
86
- response = await doFetch(TOKEN_ENDPOINT, {
87
- method: 'POST',
88
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
89
- body: body.toString(),
90
- });
91
- }
92
- catch (err) {
93
- // Transport failure — Linear is unreachable. Not a configuration problem, so
94
- // this stays a plain Error and classifies as an unexpected failure (exit 2).
95
- throw new Error(`Linear token mint failed: ${err instanceof Error ? err.message : String(err)}`);
96
- }
97
- const text = await response.text();
98
- if (!response.ok) {
99
- // 4xx means Linear rejected these credentials or scopes — the operator can fix
100
- // that. 5xx is an outage, and 429 is rate limiting: both are transient and must
101
- // not be blamed on the config.
102
- const message = `Linear token mint rejected (HTTP ${response.status})`;
103
- const transient = response.status >= 500 || response.status === 429;
104
- throw transient ? new Error(message) : new LinearConfigError(message);
105
- }
106
- let parsed;
107
- try {
108
- parsed = JSON.parse(text);
109
- }
110
- catch {
111
- throw new Error(`Linear token mint returned a non-JSON response (HTTP ${response.status})`);
112
- }
113
- const token = parsed.access_token;
114
- if (typeof token !== 'string' || token.length === 0) {
115
- throw new Error('Linear token mint returned no access_token');
116
- }
117
- return token;
118
- }
119
- export async function resolveLinearAuth(config, creds, opts = {}) {
120
- const product = opts.product ?? DEFAULT_PRODUCT;
121
- const { actor, signature: template } = config.identity;
122
- const signature = renderSignature(template, { actor, product });
123
- if (config.auth.mode === 'client_credentials') {
124
- const missing = [];
125
- if (!creds.clientId)
126
- missing.push(config.auth.client_id_env);
127
- if (!creds.clientSecret)
128
- missing.push(config.auth.client_secret_env);
129
- if (missing.length > 0) {
130
- // Abort rather than fall back — see the module header.
131
- throw new LinearConfigError(`Linear auth mode is client_credentials but ${missing.join(' and ')} ` +
132
- `${missing.length > 1 ? 'are' : 'is'} not set. ` +
133
- 'Set them, or switch linear.auth.mode to api_key.');
134
- }
135
- let token;
136
- try {
137
- token = await mintAppToken({ clientId: creds.clientId, clientSecret: creds.clientSecret, scopes: config.auth.scopes }, opts);
138
- }
139
- catch (err) {
140
- // Preserve the classification the mint chose: a rejected credential stays a
141
- // config error (exit 1), an outage stays unexpected (exit 2). Both abort —
142
- // neither falls back to api_key.
143
- // Name the variables to check. A bare "HTTP 401" leaves an operator with
144
- // custom env names guessing which credential to rotate. Names only — never
145
- // the values.
146
- const message = `Linear client_credentials token mint failed — aborting rather than falling back ` +
147
- `to an API key (that would attribute agent writes to a human). ` +
148
- `Check ${config.auth.client_id_env} and ${config.auth.client_secret_env}. ` +
149
- `${err instanceof Error ? err.message : String(err)}`;
150
- throw isLinearConfigError(err) ? new LinearConfigError(message) : new Error(message);
151
- }
152
- return {
153
- mode: 'client_credentials', token, bearer: true, actor, signature,
154
- createAsUser: actor, signatureTemplate: template, product,
155
- };
156
- }
157
- if (!creds.apiKey) {
158
- throw new LinearConfigError(`Linear is enabled but ${config.auth.api_key_env} is not set. ` +
159
- `Set it, or disable the linear block in your config.`);
160
- }
161
- return {
162
- mode: 'api_key', token: creds.apiKey, bearer: false, actor, signature,
163
- signatureTemplate: template, product,
164
- };
165
- }
166
- // Derives a step-scoped identity: `crosscheck` → `crosscheck/review`.
167
- //
168
- // The epic calls for per-worker display names (its example is `symphony/worker-3`)
169
- // so a fleet of agents does not collapse into one indistinguishable bot. crosscheck's
170
- // natural axis is the workflow step that produced the write.
171
- //
172
- // T1 re-points createAsUser, which is what Linear actually renders. T0 has no
173
- // createAsUser, so the suffix only reaches the signature line — still an improvement,
174
- // since that is T0's whole attribution mechanism.
175
- export function withWorker(auth, worker) {
176
- const trimmed = worker.trim();
177
- if (!trimmed)
178
- return auth;
179
- const actor = `${auth.actor}/${trimmed}`;
180
- return {
181
- ...auth,
182
- actor,
183
- signature: renderSignature(auth.signatureTemplate, { actor, product: auth.product }),
184
- ...(auth.createAsUser !== undefined && { createAsUser: actor }),
185
- };
186
- }
187
- //# sourceMappingURL=identity.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/linear/identity.ts"],"names":[],"mappings":"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"}
@@ -1,35 +0,0 @@
1
- import { type LinearRequestOptions } from './client.js';
2
- import { type ResolvedLinearAuth } from './identity.js';
3
- import type { LinearConfig } from '../config/schema.js';
4
- export type LinearNotifyStatus = 'posted' | 'skipped' | 'failed';
5
- export interface LinearNotifyResult {
6
- status: LinearNotifyStatus;
7
- /** Machine-readable reason for skipped/failed. */
8
- reason?: string;
9
- identifier?: string;
10
- url?: string;
11
- }
12
- export interface LinearNotifyParams {
13
- auth: ResolvedLinearAuth;
14
- config: LinearConfig;
15
- pr: {
16
- branch?: string;
17
- title: string;
18
- body?: string;
19
- url: string;
20
- sha?: string;
21
- };
22
- verdict: string | null;
23
- reviewer: string;
24
- origin: string;
25
- model: string;
26
- summary?: string;
27
- service?: string;
28
- /** Workflow step that produced this verdict. Defaults to 'review'. */
29
- stepType?: string;
30
- /** 1-based workflow round. Defaults to 1. */
31
- round?: number;
32
- }
33
- export declare function issueBelongsToWorkspace(issueUrl: string, workspace: string): boolean;
34
- export declare function notifyLinear(params: LinearNotifyParams, opts?: LinearRequestOptions): Promise<LinearNotifyResult>;
35
- //# sourceMappingURL=notify.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/linear/notify.ts"],"names":[],"mappings":"AASA,OAAO,EAA4C,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAEjG,OAAO,EAA+B,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAA;AAEhE,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,kBAAkB,CAAA;IAC1B,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,kBAAkB,CAAA;IACxB,MAAM,EAAE,YAAY,CAAA;IACpB,EAAE,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAGD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAQpF;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,kBAAkB,EAC1B,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAwD7B"}
@@ -1,76 +0,0 @@
1
- // Orchestrates the one Linear write crosscheck makes: mirroring a review verdict
2
- // onto the Linear issue the PR belongs to.
3
- //
4
- // This never throws. Auth is resolved up front (fail-fast, before the expensive
5
- // review runs), so anything that goes wrong here is a per-write problem on a review
6
- // that already succeeded and already posted to GitHub. The caller logs the returned
7
- // status — failures are reported, never swallowed.
8
- import { buildLinearCommentBody, shouldPostToLinear } from './comment.js';
9
- import { findIssueByIdentifier, postLinearComment } from './client.js';
10
- import { extractLinearRef } from './ref.js';
11
- import { renderIcon, renderSignature } from './identity.js';
12
- // Linear issue URLs are https://linear.app/<workspace>/issue/<ID>/<slug>.
13
- export function issueBelongsToWorkspace(issueUrl, workspace) {
14
- try {
15
- const segments = new URL(issueUrl).pathname.split('/').filter(Boolean);
16
- return segments[0]?.toLowerCase() === workspace.toLowerCase();
17
- }
18
- catch {
19
- // Unparseable URL from the API — fail closed rather than post to the wrong place.
20
- return false;
21
- }
22
- }
23
- export async function notifyLinear(params, opts = {}) {
24
- const { auth, config, pr } = params;
25
- if (!shouldPostToLinear(params.verdict, config.comment_on)) {
26
- return { status: 'skipped', reason: 'verdict-not-configured' };
27
- }
28
- const ref = extractLinearRef({ branch: pr.branch, title: pr.title, body: pr.body }, config.team_keys);
29
- if (!ref)
30
- return { status: 'skipped', reason: 'no-issue-ref' };
31
- try {
32
- const issue = await findIssueByIdentifier(auth, ref.id, opts);
33
- if (!issue)
34
- return { status: 'skipped', reason: 'issue-not-found', identifier: ref.id };
35
- // An explicit URL names a workspace, and identifiers repeat across workspaces.
36
- // If the credentials resolve a different workspace, this is a same-numbered
37
- // issue somewhere else — never the one the PR pointed at. Checked before any
38
- // body is built, so a mismatch costs nothing.
39
- if (ref.workspace && !issueBelongsToWorkspace(issue.url, ref.workspace)) {
40
- return { status: 'skipped', reason: 'workspace-mismatch', identifier: ref.id };
41
- }
42
- // Re-render here rather than reusing auth.signature: this is the first point
43
- // that knows the model and reviewer, which the template may reference.
44
- const signature = renderSignature(auth.signatureTemplate, {
45
- actor: auth.actor,
46
- product: auth.product,
47
- model: params.model === 'default' ? undefined : params.model,
48
- reviewer: params.reviewer,
49
- icon: renderIcon(config.identity.icon_url),
50
- });
51
- const body = buildLinearCommentBody({
52
- signature,
53
- verdict: params.verdict,
54
- reviewer: params.reviewer,
55
- origin: params.origin,
56
- model: params.model,
57
- prUrl: pr.url,
58
- prTitle: pr.title,
59
- ...(pr.sha && { sha: pr.sha }),
60
- ...(params.stepType && { stepType: params.stepType }),
61
- ...(params.round !== undefined && { round: params.round }),
62
- ...(params.summary && { summary: params.summary }),
63
- ...(params.service && { service: params.service }),
64
- });
65
- const comment = await postLinearComment(auth, issue.id, body, opts);
66
- return { status: 'posted', identifier: issue.identifier, url: comment.url };
67
- }
68
- catch (err) {
69
- return {
70
- status: 'failed',
71
- reason: err instanceof Error ? err.message : String(err),
72
- identifier: ref.id,
73
- };
74
- }
75
- }
76
- //# sourceMappingURL=notify.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"notify.js","sourceRoot":"","sources":["../../src/linear/notify.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,2CAA2C;AAC3C,EAAE;AACF,gFAAgF;AAChF,oFAAoF;AACpF,oFAAoF;AACpF,mDAAmD;AAEnD,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACzE,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAA6B,MAAM,aAAa,CAAA;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,eAAe,EAA2B,MAAM,eAAe,CAAA;AA6BpF,0EAA0E;AAC1E,MAAM,UAAU,uBAAuB,CAAC,QAAgB,EAAE,SAAiB;IACzE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACtE,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,SAAS,CAAC,WAAW,EAAE,CAAA;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,kFAAkF;QAClF,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAA0B,EAC1B,OAA6B,EAAE;IAE/B,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,CAAA;IAEnC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAA;IAChE,CAAC;IAED,MAAM,GAAG,GAAG,gBAAgB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IACrG,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IAE9D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QAC7D,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,EAAE,CAAA;QAEvF,+EAA+E;QAC/E,4EAA4E;QAC5E,6EAA6E;QAC7E,8CAA8C;QAC9C,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACxE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,oBAAoB,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,EAAE,CAAA;QAChF,CAAC;QAED,6EAA6E;QAC7E,uEAAuE;QACvE,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,iBAAiB,EAAE;YACxD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK;YAC5D,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;SAC3C,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,sBAAsB,CAAC;YAClC,SAAS;YACT,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,KAAK,EAAE,EAAE,CAAC,GAAG;YACb,OAAO,EAAE,EAAE,CAAC,KAAK;YACjB,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;YAC9B,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrD,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YAC1D,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;YAClD,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;SACnD,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QACnE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAA;IAC7E,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO;YACL,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;YACxD,UAAU,EAAE,GAAG,CAAC,EAAE;SACnB,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -1,13 +0,0 @@
1
- import { type TicketRef } from '../issues/ticket-ref.js';
2
- export interface LinearIssueRef extends TicketRef {
3
- source: 'branch' | 'title' | 'body';
4
- /** Workspace slug, when the ref came from an explicit URL. Bare refs have none. */
5
- workspace?: string;
6
- }
7
- export interface PRMetadata {
8
- branch?: string | null;
9
- title?: string | null;
10
- body?: string | null;
11
- }
12
- export declare function extractLinearRef(pr: PRMetadata, teamKeys: readonly string[]): LinearIssueRef | null;
13
- //# sourceMappingURL=ref.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../../src/linear/ref.ts"],"names":[],"mappings":"AAYA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAE1F,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAA;IACnC,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAiED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,GAAG,IAAI,CAanG"}
@@ -1,90 +0,0 @@
1
- // Write-side ref resolution: which Linear issue should crosscheck comment on?
2
- //
3
- // Extraction primitives live in src/issues/ticket-ref.ts and are reused here —
4
- // this module only adds the two things the write path needs on top:
5
- //
6
- // 1. linear.app issue URLs, which are unambiguous and so need no configuration.
7
- // 2. A stricter policy for bare identifiers: they are only honoured for team keys
8
- // the operator has configured. Enrichment can afford to match `UTF-8` and let
9
- // the lookup return nothing, because a failed read is a no-op. A failed *write*
10
- // would post a review comment onto an unrelated issue, so the write path
11
- // requires the operator to name their team keys first.
12
- import { extractTicketRefs, parseTicketId } from '../issues/ticket-ref.js';
13
- // The identifier occupies one whole path segment. Lookaheads kept getting this
14
- // wrong in both directions: requiring `/` or end-of-path missed `IN-42.` at the
15
- // end of a sentence, and allowing any non-alphanumeric accepted `IN-123-typo` as
16
- // `IN-123`. Take the segment, strip trailing sentence punctuation, and require
17
- // parseTicketId to match it whole.
18
- const ISSUE_SEGMENTS = /^\/([^/]+)\/issue\/([^/]+)/i;
19
- // Leading punctuation is safe to allow — but only characters that cannot be part
20
- // of a hostname, so `notlinear.app` still cannot match. Missing `(linear.app/...)`
21
- // made it fall through to the bare-ID extractor, which returns no workspace and
22
- // so silently loses the workspace-mismatch protection.
23
- const BARE_URL = /(?:^|[\s([{<"'`,;])linear\.app\/([^/\s]+)\/issue\/([^/\s]+)/gi;
24
- // Absolute URLs are parsed and their hostname compared exactly. A boundary check
25
- // on the text is not enough: `https://evil.example/linear.app/acme/issue/IN-1`
26
- // satisfies any "character before linear.app" rule while pointing somewhere else.
27
- const ABSOLUTE_URL = /\bhttps?:\/\/[^\s<>()"'`]+/gi;
28
- /** Trailing sentence punctuation is never part of an identifier. */
29
- function stripTrailingPunctuation(segment) {
30
- return segment.replace(/[.,;:!?)\]}>'"]+$/, '');
31
- }
32
- function fromUrl(text) {
33
- for (const match of text.matchAll(ABSOLUTE_URL)) {
34
- let parsed;
35
- try {
36
- parsed = new URL(match[0]);
37
- }
38
- catch {
39
- continue;
40
- }
41
- if (parsed.hostname.toLowerCase() !== 'linear.app')
42
- continue;
43
- const segments = parsed.pathname.match(ISSUE_SEGMENTS);
44
- if (!segments)
45
- continue;
46
- const ref = parseTicketId(stripTrailingPunctuation(segments[2]));
47
- if (ref)
48
- return withWorkspace(ref, segments[1]);
49
- }
50
- // Iterate, like the absolute-URL path above: a malformed candidate earlier in
51
- // the text must not stop a valid one later from resolving.
52
- for (const bare of text.matchAll(BARE_URL)) {
53
- const ref = parseTicketId(stripTrailingPunctuation(bare[2]));
54
- if (ref)
55
- return withWorkspace(ref, bare[1]);
56
- }
57
- return null;
58
- }
59
- // An explicit URL names a workspace. Identifiers are only unique within one, so
60
- // dropping the slug lets a URL for workspace A resolve against credentials for
61
- // workspace B and comment on B's same-numbered issue.
62
- function withWorkspace(ref, workspace) {
63
- return { ...ref, workspace: workspace.toLowerCase(), source: 'body' };
64
- }
65
- function matchField(text, teamKeys) {
66
- const url = fromUrl(text);
67
- if (url)
68
- return url;
69
- // Bare identifiers only for configured keys — see the module header.
70
- if (teamKeys.length === 0)
71
- return null;
72
- const bare = extractTicketRefs({ title: text }, [...teamKeys])[0];
73
- return bare ? { ...bare, source: 'body' } : null;
74
- }
75
- export function extractLinearRef(pr, teamKeys) {
76
- const fields = [
77
- [pr.branch, 'branch'],
78
- [pr.title, 'title'],
79
- [pr.body, 'body'],
80
- ];
81
- for (const [text, source] of fields) {
82
- if (!text)
83
- continue;
84
- const ref = matchField(text, teamKeys);
85
- if (ref)
86
- return { ...ref, source };
87
- }
88
- return null;
89
- }
90
- //# sourceMappingURL=ref.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ref.js","sourceRoot":"","sources":["../../src/linear/ref.ts"],"names":[],"mappings":"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"}
@@ -1,26 +0,0 @@
1
- import { type LinearAuthMode, type LinearCredentials, type ResolveOptions, type ResolvedLinearAuth } from './identity.js';
2
- import { type LinearRequestOptions } from './client.js';
3
- import type { LinearConfig } from '../config/schema.js';
4
- export interface LinearIdentityReport {
5
- ok: boolean;
6
- mode: LinearAuthMode;
7
- /** Actor name writes will carry, including any per-step suffix the caller applies. */
8
- actor: string;
9
- organization?: string;
10
- /**
11
- * 'app' — writes render as the OAuth application (botActor). The goal state.
12
- * 'user' — writes attribute to a human account. What IN-2271 is eliminating.
13
- */
14
- attribution: 'app' | 'user';
15
- /** In api_key mode, the human account writes currently attribute to. */
16
- attributesTo?: string;
17
- /** Populated when ok is false. Never contains credential material. */
18
- error?: string;
19
- /**
20
- * The identity this probe resolved, so callers can reuse it instead of minting
21
- * a second token. Absent when resolution failed.
22
- */
23
- auth?: ResolvedLinearAuth;
24
- }
25
- export declare function verifyLinearIdentity(config: LinearConfig, creds: LinearCredentials, opts?: ResolveOptions & LinearRequestOptions): Promise<LinearIdentityReport>;
26
- //# sourceMappingURL=verify.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/linear/verify.ts"],"names":[],"mappings":"AAWA,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAC5I,OAAO,EAAiB,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,cAAc,CAAA;IACpB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,WAAW,EAAE,KAAK,GAAG,MAAM,CAAA;IAC3B,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAA;CAC1B;AAQD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,iBAAiB,EACxB,IAAI,GAAE,cAAc,GAAG,oBAAyB,GAC/C,OAAO,CAAC,oBAAoB,CAAC,CAoD/B"}
@@ -1,67 +0,0 @@
1
- // Answers the one question a deployment cutover needs answered (IN-2271):
2
- // when this daemon writes to Linear, whose name is on it?
3
- //
4
- // The acceptance criterion for switching Humanbased's deployments to the HB Agent
5
- // Gateway is "zero writes from symphony/crosscheck attribute to a human account".
6
- // That is checkable ahead of time — resolve the identity, confirm the token is
7
- // accepted, and report what the write would render as.
8
- //
9
- // Never throws. A verification that fails is a report with ok: false, because the
10
- // caller is a status command that must still print the rest of its output.
11
- import { resolveLinearAuth } from './identity.js';
12
- import { linearGraphQL } from './client.js';
13
- const ORG_QUERY = `query { organization { name } }`;
14
- const VIEWER_QUERY = `query { viewer { name email } organization { name } }`;
15
- export async function verifyLinearIdentity(config, creds, opts = {}) {
16
- const mode = config.auth.mode;
17
- const attribution = mode === 'client_credentials' ? 'app' : 'user';
18
- let auth;
19
- try {
20
- auth = await resolveLinearAuth(config, creds, opts);
21
- }
22
- catch (err) {
23
- return {
24
- ok: false,
25
- mode,
26
- actor: config.identity.actor,
27
- attribution,
28
- error: err instanceof Error ? err.message : String(err),
29
- };
30
- }
31
- try {
32
- if (auth.mode === 'client_credentials') {
33
- // An app token has no viewer — it acts as itself. Reaching the org at all is
34
- // proof the minted token is accepted.
35
- const data = await linearGraphQL(auth, ORG_QUERY, {}, opts);
36
- return {
37
- ok: true,
38
- mode: auth.mode,
39
- actor: auth.actor,
40
- attribution: 'app',
41
- auth,
42
- ...(data.organization && { organization: data.organization.name }),
43
- };
44
- }
45
- const data = await linearGraphQL(auth, VIEWER_QUERY, {}, opts);
46
- const who = data.viewer?.email ?? data.viewer?.name ?? undefined;
47
- return {
48
- ok: true,
49
- mode: auth.mode,
50
- actor: auth.actor,
51
- attribution: 'user',
52
- auth,
53
- ...(data.organization && { organization: data.organization.name }),
54
- ...(who && { attributesTo: who }),
55
- };
56
- }
57
- catch (err) {
58
- return {
59
- ok: false,
60
- mode: auth.mode,
61
- actor: auth.actor,
62
- attribution,
63
- error: err instanceof Error ? err.message : String(err),
64
- };
65
- }
66
- }
67
- //# sourceMappingURL=verify.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/linear/verify.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,0DAA0D;AAC1D,EAAE;AACF,kFAAkF;AAClF,kFAAkF;AAClF,+EAA+E;AAC/E,uDAAuD;AACvD,EAAE;AACF,kFAAkF;AAClF,2EAA2E;AAE3E,OAAO,EAAE,iBAAiB,EAA6F,MAAM,eAAe,CAAA;AAC5I,OAAO,EAAE,aAAa,EAA6B,MAAM,aAAa,CAAA;AAyBtE,MAAM,SAAS,GAAG,iCAAiC,CAAA;AACnD,MAAM,YAAY,GAAG,uDAAuD,CAAA;AAK5E,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAoB,EACpB,KAAwB,EACxB,OAA8C,EAAE;IAEhD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAA;IAC7B,MAAM,WAAW,GAAG,IAAI,KAAK,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAA;IAElE,IAAI,IAAI,CAAA;IACR,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;IACrD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI;YACJ,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK;YAC5B,WAAW;YACX,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;YACvC,6EAA6E;YAC7E,sCAAsC;YACtC,MAAM,IAAI,GAAG,MAAM,aAAa,CAAc,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;YACxE,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,KAAK;gBAClB,IAAI;gBACJ,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;aACnE,CAAA;QACH,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,aAAa,CAAiB,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;QAC9E,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,SAAS,CAAA;QAChE,OAAO;YACL,EAAE,EAAE,IAAI;YACR,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,MAAM;YACnB,IAAI;YACJ,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YAClE,GAAG,CAAC,GAAG,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;SAClC,CAAA;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW;YACX,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -1,4 +0,0 @@
1
- import type { SkillMetadata } from './broker.js';
2
- export declare function formatSkillAttribution(skills: SkillMetadata[]): string;
3
- export declare function renderSkillAttributionLine(skills: SkillMetadata[]): string;
4
- //# sourceMappingURL=attribution.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../../src/skills/attribution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAIhD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAEtE;AAID,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAG1E"}
@@ -1,14 +0,0 @@
1
- import { formatSkillIdentity } from './catalog.js';
2
- // Skills are separated by a middot and kept on one line: the receipt has to be
3
- // present for licensing, but it is metadata about the run, not part of it.
4
- export function formatSkillAttribution(skills) {
5
- return skills.map(formatSkillIdentity).join(' · ');
6
- }
7
- // One italic line, same weight as the reviewer attribution it sits beneath.
8
- // Empty string when nothing activated, so callers can concatenate blind.
9
- export function renderSkillAttributionLine(skills) {
10
- if (skills.length === 0)
11
- return '';
12
- return `_Skills: ${formatSkillAttribution(skills)}_`;
13
- }
14
- //# sourceMappingURL=attribution.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/skills/attribution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAGlD,+EAA+E;AAC/E,2EAA2E;AAC3E,MAAM,UAAU,sBAAsB,CAAC,MAAuB;IAC5D,OAAO,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACpD,CAAC;AAED,4EAA4E;AAC5E,yEAAyE;AACzE,MAAM,UAAU,0BAA0B,CAAC,MAAuB;IAChE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAClC,OAAO,YAAY,sBAAsB,CAAC,MAAM,CAAC,GAAG,CAAA;AACtD,CAAC"}
@@ -1,2 +0,0 @@
1
- export declare function runSkillBrokerProxy(socketPath: string): Promise<void>;
2
- //# sourceMappingURL=broker-server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"broker-server.d.ts","sourceRoot":"","sources":["../../src/skills/broker-server.ts"],"names":[],"mappings":"AASA,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3E"}
@@ -1,17 +0,0 @@
1
- import { once } from 'events';
2
- import { createConnection } from 'net';
3
- function parseSocketPath(argv) {
4
- const index = argv.indexOf('--socket');
5
- if (index === -1 || !argv[index + 1])
6
- throw new Error('--socket <path> is required');
7
- return argv[index + 1];
8
- }
9
- export async function runSkillBrokerProxy(socketPath) {
10
- const socket = createConnection(socketPath);
11
- await once(socket, 'connect');
12
- process.stdin.pipe(socket);
13
- socket.pipe(process.stdout);
14
- await once(socket, 'close');
15
- }
16
- await runSkillBrokerProxy(parseSocketPath(process.argv.slice(2)));
17
- //# sourceMappingURL=broker-server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"broker-server.js","sourceRoot":"","sources":["../../src/skills/broker-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAA;AAEtC,SAAS,eAAe,CAAC,IAAc;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACtC,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;IACpF,OAAO,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,UAAkB;IAC1D,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC3C,MAAM,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC7B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC1B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,mBAAmB,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA"}