Repository navigation
Self-hosting and Oauth (CYPACK-669) - #707
Merged
Merged
Conversation
Implements automatic OAuth token refresh with the setHeader pattern: - LinearIssueTrackerService patches client.request to intercept 401 errors and retry with refreshed token using client.setHeader - EdgeWorker manages token refresh with promise coalescing to prevent concurrent refresh attempts - Adds linearRefreshToken field to RepositoryConfig - IIssueTrackerService gains setAccessToken method for external token updates - Tests verify token refresh behavior and mock LinearClient properly Clean implementation on upstream/main with minimal changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous implementation had a race condition where concurrent 401 errors would each trigger separate token refresh attempts. This fix: 1. Keeps the refresh promise around after resolution so ALL concurrent 401 errors share the same refreshed token 2. Only clears the promise on refresh failure, allowing fresh retry 3. Adds isRetry flag to prevent infinite retry loops 4. Adds guards for test mocks that don't have .client property 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactored OAuth token refresh to be fully encapsulated within LinearIssueTrackerService (packages/linear-event-transport), removing all refresh logic from EdgeWorker (packages/edge-worker). LinearIssueTrackerService now handles: - Token refresh HTTP calls to Linear OAuth endpoint - Workspace-level coalescing via static `pendingRefreshes` map - Shared refresh token state via static `workspaceRefreshTokens` map - Per-instance LinearClient header updates EdgeWorker's remaining role (minimal, cannot be removed): - Passes initial credentials via LinearOAuthConfig - onTokenRefresh callback ONLY persists to config.json NOTE: EdgeWorker owns config.json, so we cannot completely remove it from the token flow. The onTokenRefresh callback is the minimum interface needed - LinearIssueTrackerService emits when tokens change, EdgeWorker persists them. All actual refresh logic is in LinearIssueTrackerService. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- SelfAuthCommand: OAuth flow for authenticating with Linear directly from CLI - SelfAddRepoCommand: Clone repository and add it to config with workspace selection - Comprehensive test coverage for both commands (33 tests total) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Complete setup guide for self-hosted Cyrus deployments - Steps 6 and 7 use new CLI commands: cyrus self-auth, cyrus self-add-repo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove all 'any' types from SelfAddRepoCommand.ts and SelfAuthCommand.ts - Add DEFAULT_WORKTREES_DIR and DEFAULT_BASE_BRANCH constants - Trim OAuth scopes to write,app:assignable,app:mentionable - Replace http.createServer with Fastify in SelfAuthCommand.ts - Use LinearClient SDK for fetchWorkspaceInfo instead of raw fetch - Rename updateConfig to overwriteRepoConfigTokens - Add url/workspace documentation comments in app.ts - Add finally block and OAuth doc comments in LinearIssueTrackerService.ts - Fix selfhosting README numbering (2.1/2.2 → 1.1/1.2) - Remove destructive tmux kill-server command from README - Delete obsolete plan docs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migrated test mocks from Node http.createServer to Fastify, matching the implementation changes from PR #656 review. Also updated LinearClient SDK mock for workspace info tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
cyrusagent
force-pushed
the
cypack-669
branch
from
December 28, 2025 19:36
9a3bf0d to
1a0c16c
Compare
- Add DEFAULT_WORKTREES_DIR, DEFAULT_BASE_BRANCH, DEFAULT_CONFIG_FILENAME constants to cyrus-core package for consistent usage across codebase - Update SelfAddRepoCommand.ts, SelfAuthCommand.ts, Application.ts, and apps/f1/server.ts to use the shared constants - Improve self-add-repo command description to document URL and workspace parameters directly in the CLI help output - Fix LinearClient mock in SelfAuthCommand tests to preserve other @linear/sdk exports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move selfhosting/README.md to docs/SELF_HOSTING.md - Extract config.json reference to docs/CONFIG_FILE.md - Extract Cloudflare tunnel setup to docs/CLOUDFLARE_TUNNEL.md (optional) - Update main README.md with documentation links - Delete selfhosting/ folder 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The shared constants move doesn't warrant an internal changelog entry. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Connoropolous
approved these changes
Dec 28, 2025
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
3 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR addresses all 18 code review change requests from PR #656 (oauth-for-cedar from grandmore/cyrus-self-hosting) to prepare the branch for merging.
Changes Made
Type Safety Improvements:
anytypes fromSelfAddRepoCommand.ts- added properEdgeConfigandWorkspaceCredentialstypesanytypes fromSelfAuthCommand.ts- added properEdgeConfigtypeWorkspaceCredentialsinterface for type-safe workspace credential handlingConfiguration Constants:
DEFAULT_WORKTREES_DIR,DEFAULT_BASE_BRANCH,DEFAULT_CONFIG_FILENAME) tocyrus-corepackage for global reusecyrus-coreinstead of being defined locallyOAuth Improvements:
write,app:assignable,app:mentionable(matching hosted version)Framework Migration:
http.createServerwith Fastify for the OAuth callback serverSDK Usage:
fetchcall withLinearClientSDK forfetchWorkspaceInfoCode Clarity:
updateConfigtooverwriteRepoConfigTokensfor clarityurlandworkspaceparameters inapp.tsfinallyblock behavior inLinearIssueTrackerService.tsDocumentation Restructure:
docs/folder for documentationselfhosting/README.mdtodocs/SELF_HOSTING.mddocs/CONFIG_FILE.mddocs/CLOUDFLARE_TUNNEL.md(now marked as optional)selfhosting/folderDocumentation Fixes:
tmux kill-servercommand from READMETest Plan
self-authandself-add-repocommands with custom--cyrus-homepathRebased
This PR has been rebased on latest
mainbranch with merge conflicts resolved.🤖 Generated with Claude Code