feat(linear): add Linear worker dispatch and trigger handlers#1100
feat(linear): add Linear worker dispatch and trigger handlers#1100zbigniewsobiecki merged 2 commits intodevfrom
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
Solid implementation that follows the established JIRA/Trello trigger patterns closely. No blocking issues — CI passes, types align, and the architectural approach is correct. Three should-fix items around code duplication and dead code.
Should Fix
-
src/triggers/linear/comment-mention.ts:83-107 — Bot identity resolution is duplicated.
resolveLinearBotUserId()insrc/router/bot-identity-resolvers.tsalready resolves the bot's Linear user ID via the exact sameviewerGraphQL query, with a 60s TTLBotIdentityCache. The trigger handler re-implements this logic inline with a rawfetchand no caching. While the worker-per-container model limits the performance impact, this is still duplicated logic that should use the existing function. If the display name is needed, the existing function could be extended rather than maintaining a second implementation. -
src/triggers/linear/comment-mention.ts:26-32 — The
hasMentionfunction has dead code: the comment on line 30 says "Also check plain @username patterns" but then immediately returnsfalse. The whole function reduces tobody.includes(userId). Additionally, the JSDoc (line 23) says Linear uses@[username](user:userId)while the inline comment (line 27) says@[Display Name](userId)— these are inconsistent descriptions of the mention format. Thebody.includes(userId)approach is fine in practice (Linear IDs are UUIDs), but the dead code and conflicting docs should be cleaned up. -
src/triggers/linear/types.ts:91 —
STATUS_TO_AGENTis duplicated verbatim between Linear and JIRA types (src/triggers/jira/types.ts). This is a maintenance risk — if a new status-to-agent mapping is added, it must be updated in both places. Consider extracting to a shared constant insrc/triggers/shared/.
🕵️ claude-code · claude-opus-4-6 · run details
- Extract STATUS_TO_AGENT to src/triggers/shared/status-to-agent.ts and re-export from jira/types.ts and linear/types.ts to eliminate duplication - Replace inline Linear viewer query in comment-mention.ts with the existing resolveLinearBotUserId() from bot-identity-resolvers.ts (cached, no raw fetch) - Clean up hasMention(): remove dead code branch and fix inconsistent JSDoc Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
LGTM — Clean, well-structured addition of Linear trigger handlers that closely follows the established JIRA/Trello patterns. The refactoring of STATUS_TO_AGENT into src/triggers/shared/status-to-agent.ts is a good deduplication move, and the JIRA re-export maintains backward compatibility.
All three trigger handlers (status-changed, label-added, comment-mention) correctly implement the TriggerHandler interface with appropriate matches() guards and handle() logic. The worker dispatch, reaction no-op, and test updates are all consistent with existing patterns. CI is green.
Minor observations (not blocking):
- The registration ordering comment in
register.ts("LinearCommentMentionTrigger must be registered before the status-changed trigger so it gets first crack at comment events") is technically unnecessary since comment events (type=Comment) and status change events (type=Issue) are mutually exclusive inmatches(). The ordering is harmless but the comment could be misleading. This mirrors the same pattern from JIRA registration, so it's fine for consistency. - The
LinearJobDatainterface inworker-entry.tscorrectly mirrors theLinearJobinterface insrc/router/queue.ts. Both should ideally share a single definition, but this follows the existing pattern where router and worker have their own type declarations (same as Trello/GitHub/JIRA/Sentry).
🕵️ claude-code · claude-opus-4-6 · run details
Summary
LinearJobDatainterface and'linear'case indispatchJob()insrc/worker-entry.tssrc/triggers/linear/module with status-changed, label-added, comment-mention trigger handlerssrc/triggers/linear/webhook-handler.tsdelegating toprocessPMWebhook()src/triggers/linear/register.tsand registers insrc/triggers/builtins.tssendLinearReaction()no-op tosrc/router/reactions.tswith'linear'case insendAcknowledgeReaction()extractLinearContext(),resolveLinearBotUserId(),postLinearAck()/deleteLinearAck()were already implemented in their respective filesImplementation Details
Trigger handlers follow exact JIRA/Trello patterns:
LinearStatusChangedTrigger— fires onaction=update, type=IssuewhenupdatedFrom.stateIdis present; matches newstateIdagainstLinearConfig.statuses(which stores state IDs, not names)LinearReadyToProcessLabelTrigger— fires onaction=create, type=IssueLabel; checks label name matchesreadyToProcessconfig, then maps currentstateIdto agent typeLinearCommentMentionTrigger— fires onaction=create, type=Comment; checks bot user ID mention in comment body, resolves bot identity via Linear GraphQLviewerqueryWorker dispatch —
LinearJobDatamatches the shape ofLinearJobinsrc/router/queue.ts(already existed for router-side use). ThedispatchJob()switch case callsprocessLinearWebhook().Test plan
tests/unit/triggers/builtins.test.tsupdated with Linear trigger mocks and count updated from 21 → 24npm run typecheck)npm run lint)Trello card: https://trello.com/c/69de7fc0bb516f8059fe911f
🤖 Generated with Claude Code
🕵️ claude-code · claude-sonnet-4-6 · run details