Skip to content

Commit 0c4ef82

Browse files
PaytonWebbercyrusagentclaude
authored
Refactor logging to a dedicated logger (#818)
* Fix: Disable MCP tools when disallowAllTools is true Summary subroutines (concise-summary, verbose-summary, question-answer, plan-summary, etc.) have disallowAllTools: true, but MCP tools like Linear's create_comment were still accessible because MCP config was always provided regardless of this setting. This change conditionally disables mcpConfig and mcpConfigPath when disallowAllTools is true, ensuring the agent truly has no tool access during summary subroutines. Closes CYPACK-760 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor logging to a dedicated logger * Add source context to sessions when emitting logs * Fix issue where single-turn sub-routines would silently fail by exceeding max-turns. Now, when the result message of a single-turn sub-routine is an error, the result text from the previous sub-routine is emitted to Linear as a result message. * Respect agent guidance for draft PRs and use --track for worktrees (#834) - Update gh-pr subroutine to conditionally gate `gh pr ready` based on agent guidance (respects --draft flag in workspace guidance) - Update changelog-update subroutine to include --base flag in PR creation targeting the configured base branch from context - Add --track flag to git worktree add commands to properly set upstream tracking branch Fixes issues where PRs were auto-converted from draft to ready and worktrees weren't tracking the correct upstream branch. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * Prepare release v0.2.20 (#835) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * Refactor TodoWrite formatting to support Task tools (#837) * Update @anthropic-ai/claude-agent-sdk to v0.2.34 and @anthropic-ai/sdk to v0.73.0 - Updated @anthropic-ai/claude-agent-sdk from ^0.2.7 to ^0.2.34 - Updated @anthropic-ai/sdk from ^0.71.2 to ^0.73.0 - Fixed type compatibility with new BetaUsage fields (inference_geo, iterations, stop_reason) - Updated gemini-runner adapters to handle new SDK types Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Update changelog for SDK updates Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Enable Claude Code experimental features in claude-runner - Set CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 - Set CLAUDE_CODE_ENABLE_TASKS=true - Set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 - Updated test expectations to include new env configuration Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Refactor TodoWrite formatting to support Task tools - Added formatTaskParameter() method to IMessageFormatter interface - Implemented Task tool formatting (TaskCreate, TaskUpdate, TaskList, TaskGet) in ClaudeMessageFormatter and GeminiMessageFormatter - Updated AgentSessionManager to handle Task tools as thought activities - Added comprehensive tests for Task tool formatting (20 new tests) - Marked TodoWrite as deprecated while maintaining backward compatibility - Fixed linting warnings in switch case block scope Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Fix spawn node ENOENT by passing process.env to Claude SDK The env option only contained 3 hardcoded vars, causing PATH to be missing from the spawned Claude Code process. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Cherry-pick d5d9e5a: Fix single-turn subroutine silent failures (#843) * Cherry-pick d5d9e5a: Fix single-turn subroutine silent failures Cherry-picks commit d5d9e5a from refactor/improved-logging branch. Resolves merge conflicts adapting logging refactor patterns (sessionId/log.info) to current branch patterns (linearAgentActivitySessionId/console.log). When a single-turn subroutine exits with an error (e.g. error_max_turns), AgentSessionManager now recovers by using the last completed subroutine's result via ProcedureAnalyzer.getLastSubroutineResult(), allowing the procedure to continue to completion instead of failing silently. Also adds tools config pass-through to ClaudeRunner and EdgeWorker so disallowAllTools subroutines properly disable built-in tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update changelogs for CYPACK-792 (#843) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix ClaudeRunner test env assertions after process.env spread Tests expected env to contain only 3 explicit keys, but commit 6e8d873 added ...process.env to prevent spawn ENOENT errors. Updated assertions to use expect.objectContaining() so tests verify required keys without failing on additional process.env entries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * Fix TaskCreate/TaskGet formatting, add ToolSearch/TaskOutput formatting, include task subject in TaskUpdate/TaskGet (#846) * Fix TaskCreate/TaskGet formatting for parallel execution, add ToolSearch and TaskOutput formatting TaskCreate now renders as concise checklist items (⏳ **subject**) instead of verbose multi-line format, better suited for parallel async execution. TaskGet shows subject with ID when enriched. ToolSearch renders as a thought with descriptive formatting. TaskOutput shows task status with blocking/non-blocking context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add changelog entries for CYPACK-795 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Simplify TaskUpdate/TaskGet to use task number, show ToolSearch query directly TaskUpdate and TaskGet now always display the task number (e.g. "Task #123") instead of the subject description for consistency with parallel execution. ToolSearch now shows the query directly as the parameter value, matching the pattern of other tools like Bash (command) and Read (file_path). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Revert Gemini runner formatting changes (not applicable to these tools) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Include task subject in TaskUpdate and TaskGet formatting TaskUpdate and TaskGet now display the task's short description alongside the task number (e.g., "✅ Task #3 — Fix login bug") when a subject is available, falling back to number-only when not. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Enrich TaskUpdate/TaskGet activities with task subject (CYPACK-797) (#847) * Enrich TaskUpdate/TaskGet activities with task subject from cache and result parsing TaskUpdate and TaskGet tool inputs don't include the task subject, causing Linear activities to show only "Task #3" without context. This change defers their activity posting from tool_use time to tool_result time, where subject can be sourced from: (1) a cache populated by TaskCreate results, or (2) parsing the Subject field from TaskGet result content. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add changelog entries for CYPACK-797 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Delete packages/edge-worker/test/AgentSessionManager.task-subject-enrichment.test.ts --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Payton Webber <53197664+PaytonWebber@users.noreply.github.com> * Release v0.2.21 (#848) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: unified internal message bus with platform translators (#851) * feat: implement GitHub webhook endpoint and event transport Add /github-webhook endpoint for receiving forwarded GitHub webhooks from CYHOST. When a valid @cyrusagent mention is received on a PR comment, a new Claude session is created on the PR branch. New package: cyrus-github-event-transport - GitHubEventTransport: EventEmitter-based transport with proxy (Bearer token) and signature (HMAC-SHA256) verification modes - GitHubCommentService: REST API client for posting replies to GitHub PRs - Utility functions for extracting data from GitHub webhook payloads - Handles both issue_comment and pull_request_review_comment events EdgeWorker integration: - registerGitHubEventTransport: registers /github-webhook endpoint - handleGitHubWebhook: full session creation flow (validates PR comment, finds matching repo, creates workspace, starts ClaudeRunner) - postGitHubReply: posts session results back to GitHub Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: update changelogs for GitHub webhook endpoint feature Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: use forwarded GitHub installation token for PR comment replies Updates GitHub webhook handling to extract and use the X-GitHub-Installation-Token header forwarded from CYHOST instead of relying on process.env.GITHUB_TOKEN. Changes: - Extended GitHubWebhookEvent type with optional installationToken field - GitHubEventTransport now extracts X-GitHub-Installation-Token header from incoming webhooks - EdgeWorker.postGitHubReply() prefers forwarded token over process.env.GITHUB_TOKEN - Added comprehensive tests for token extraction behavior (2 new tests) This enables self-hosted Cyrus processes to post PR comment replies using short-lived (1-hour) GitHub App installation tokens. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: use forwarded installation token in fetchPRBranchRef Update EdgeWorker.fetchPRBranchRef() to prefer event.installationToken over process.env.GITHUB_TOKEN for authenticating GitHub API calls to fetch PR branch details. This fixes 404 errors in self-hosted setups where process.env.GITHUB_TOKEN doesn't exist, allowing private repo PR details to be fetched using forwarded GitHub App installation tokens. - Changed line 866 in EdgeWorker.ts from process.env.GITHUB_TOKEN to event.installationToken || process.env.GITHUB_TOKEN - Updated comment to reflect new token preference behavior - Added comprehensive test coverage in EdgeWorker.fetchPRBranchRef.test.ts - Updated CHANGELOG.internal.md to document the change Fixes CYPACK-774 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: guard activity-posting methods for non-Linear sessions - Add externalSessionId guard to postAnalyzingThought and postProcedureSelectionThought so they skip posting (and don't error) for GitHub/Slack sessions - Remove activeWebhookCount tracking from handleMessage() to avoid double-counting with legacy webhook handlers - Normalize all activity-posting guard clauses from warn to debug level, since non-Linear sessions hitting these paths is expected behavior - Add tests verifying GitHub sessions skip all Linear activity posting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add unified internal message bus with platform translators Introduce a platform-agnostic message layer that translates webhook payloads from Linear and GitHub into a unified InternalMessage format. This enables handleMessage() in EdgeWorker to process events from all platforms through a single code path. - Add InternalMessage type system in core (SessionStart, UserPrompt, StopSignal, ContentUpdate, Unassign) with type guards and platform refs - Add IMessageTranslator interface for platform-specific translators - Implement LinearMessageTranslator and GitHubMessageTranslator - Wire translators into event transports to emit 'message' alongside legacy 'event' for backward compatibility - Replace old linear-event-transport tests with translator-focused tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: agentclear <agentops@ceedar.ai> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * Consolidate scattered message posting logic to a helper function (#854) * feat: implement GitHub webhook endpoint and event transport Add /github-webhook endpoint for receiving forwarded GitHub webhooks from CYHOST. When a valid @cyrusagent mention is received on a PR comment, a new Claude session is created on the PR branch. New package: cyrus-github-event-transport - GitHubEventTransport: EventEmitter-based transport with proxy (Bearer token) and signature (HMAC-SHA256) verification modes - GitHubCommentService: REST API client for posting replies to GitHub PRs - Utility functions for extracting data from GitHub webhook payloads - Handles both issue_comment and pull_request_review_comment events EdgeWorker integration: - registerGitHubEventTransport: registers /github-webhook endpoint - handleGitHubWebhook: full session creation flow (validates PR comment, finds matching repo, creates workspace, starts ClaudeRunner) - postGitHubReply: posts session results back to GitHub Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: update changelogs for GitHub webhook endpoint feature Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: use forwarded GitHub installation token for PR comment replies Updates GitHub webhook handling to extract and use the X-GitHub-Installation-Token header forwarded from CYHOST instead of relying on process.env.GITHUB_TOKEN. Changes: - Extended GitHubWebhookEvent type with optional installationToken field - GitHubEventTransport now extracts X-GitHub-Installation-Token header from incoming webhooks - EdgeWorker.postGitHubReply() prefers forwarded token over process.env.GITHUB_TOKEN - Added comprehensive tests for token extraction behavior (2 new tests) This enables self-hosted Cyrus processes to post PR comment replies using short-lived (1-hour) GitHub App installation tokens. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * refactor: consolidate messsage emitting to a single function --------- Co-authored-by: agentclear <agentops@ceedar.ai> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat: reuse existing worktree when branch is already checked out When a GitHub webhook arrives for a PR branch that's already checked out in a Linear session's worktree, git worktree add fails. Instead of falling back to an empty directory, detect and reuse the existing worktree path — both proactively (before attempting creation) and as a safety net (parsing the git error message in the catch block). Also adds a concurrency warning log when a GitHub session shares a workspace with an active Linear session. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Feature/add GitHub comment reaction (#860) * fix: use rawBody for GitHub webhook HMAC signature verification JSON.stringify(request.body) re-serializes parsed JSON which may differ from the original bytes GitHub signed. Use request.rawBody instead, which preserves the exact payload bytes. The rawBody config was already enabled. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: rename misleading _sessionId param to _runnerSessionId Clarifies that the parameter receives the runner session ID (Claude/Gemini), not the internal session ID. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: migrate AgentSessionManager from IIssueTrackerService to IActivitySink Decouple AgentSessionManager from Linear-specific IIssueTrackerService by routing all activity posting through the platform-agnostic IActivitySink interface. This enables future support for non-Linear activity sinks. - Expand IActivitySink with ActivitySignal, ActivityPostOptions, ActivityPostResult types - Update LinearActivitySink to map string signals to AgentActivitySignal enum - Replace issueTracker constructor param with activitySink in AgentSessionManager - Rename syncEntryToLinear → syncEntryToActivitySink - Create LinearActivitySink at both EdgeWorker construction sites - Update all test files to use IActivitySink mock pattern Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add "eyes" emoji reaction to GitHub comments that trigger agent sessions Gives users instant visual feedback that their @mention was received before the potentially long-running session begins. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: agentclear <agentops@ceedar.ai> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b3441a2 commit 0c4ef82

85 files changed

Lines changed: 9793 additions & 3367 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.internal.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,34 @@ This changelog documents internal development changes, refactors, tooling update
55
## [Unreleased]
66

77
### Changed
8+
- Refactored logging across all packages to use a dedicated `ILogger` interface and `Logger` implementation in `packages/core/src/logging/`. Replaced direct `console.log`/`console.error` calls in EdgeWorker, AgentSessionManager, ClaudeRunner, GitService, RepositoryRouter, SharedApplicationServer, SharedWebhookServer, WorktreeIncludeService, ProcedureAnalyzer, AskUserQuestionHandler, LinearEventTransport, and LinearIssueTrackerService with structured logger calls. Log level is configurable via the `CYRUS_LOG_LEVEL` environment variable (DEBUG, INFO, WARN, ERROR, SILENT).
9+
- Added source context (session ID, platform, issue identifier, repository) to log messages via `logger.withContext()`, enabling easier debugging and log filtering across concurrent sessions
810
- Updated `CyrusAgentSession` schema to v3.0: renamed `linearAgentActivitySessionId` to `id`, added optional `externalSessionId` for tracker-specific IDs, added optional `issueContext` object for issue metadata, made `issue` and `issueId` optional to support standalone sessions ([CYPACK-728](https://linear.app/ceedar/issue/CYPACK-728), [#770](https://github.com/ceedaragents/cyrus/pull/770))
911
- Updated `PersistenceManager` to v3.0 format with automatic migration from v2.0, preserving all existing session data during migration ([CYPACK-728](https://linear.app/ceedar/issue/CYPACK-728), [#770](https://github.com/ceedaragents/cyrus/pull/770))
12+
- GitHub webhook handling now uses forwarded installation tokens: `GitHubEventTransport` extracts `X-GitHub-Installation-Token` header from CYHOST webhooks and includes it in emitted events, `EdgeWorker.postGitHubReply()` and `EdgeWorker.fetchPRBranchRef()` prefer the forwarded token over `process.env.GITHUB_TOKEN`, enabling self-hosted Cyrus instances to post PR comment replies and fetch PR branch details using short-lived (1-hour) GitHub App installation tokens ([CYPACK-773](https://linear.app/ceedar/issue/CYPACK-773), [#821](https://github.com/ceedaragents/cyrus/pull/821), [CYPACK-774](https://linear.app/ceedar/issue/CYPACK-774), [#822](https://github.com/ceedaragents/cyrus/pull/822))
1013

1114
### Added
15+
- New `cyrus-github-event-transport` package: EventEmitter-based transport for receiving and verifying forwarded GitHub webhooks, with proxy (Bearer token) and signature (HMAC-SHA256) verification modes, a `GitHubCommentService` for posting replies via GitHub REST API, and utility functions for extracting webhook payload data. ([CYPACK-772](https://linear.app/ceedar/issue/CYPACK-772), [#820](https://github.com/ceedaragents/cyrus/pull/820))
16+
- EdgeWorker GitHub webhook integration: `/github-webhook` endpoint, session creation flow for PR comments, git worktree checkout for PR branches, and reply posting via GitHub API. ([CYPACK-772](https://linear.app/ceedar/issue/CYPACK-772), [#820](https://github.com/ceedaragents/cyrus/pull/820))
17+
- Subroutine result text is now stored in procedure history when advancing between subroutines. On error results (e.g. `error_max_turns` from single-turn subroutines), `AgentSessionManager` recovers by using the last completed subroutine's result via `ProcedureAnalyzer.getLastSubroutineResult()`, allowing the procedure to continue to completion instead of failing
1218
- Created `GlobalSessionRegistry` class for centralized session storage across all repositories, enabling cross-repository session lookups in orchestrator workflows ([CYPACK-725](https://linear.app/ceedar/issue/CYPACK-725), [#766](https://github.com/ceedaragents/cyrus/pull/766))
1319
- Extracted `IActivitySink` interface and `LinearActivitySink` implementation to decouple activity posting from `IIssueTrackerService`, enabling multiple activity sinks to receive session activities ([CYPACK-726](https://linear.app/ceedar/issue/CYPACK-726), [#767](https://github.com/ceedaragents/cyrus/pull/767))
1420
- Integrated `GlobalSessionRegistry` with `EdgeWorker`, making it the single source of truth for parent-child session mappings and cross-repository session lookups ([CYPACK-727](https://linear.app/ceedar/issue/CYPACK-727), [#769](https://github.com/ceedaragents/cyrus/pull/769))
1521

22+
## [0.2.21] - 2026-02-09
23+
24+
### Changed
25+
- Refactored formatting strategy from TodoWrite to Task tools (TaskCreate, TaskUpdate, TaskList, TaskGet). Added `formatTaskParameter()` method to IMessageFormatter interface and updated AgentSessionManager to handle Task tools as thought activities. ([CYPACK-788](https://linear.app/ceedar/issue/CYPACK-788), [#837](https://github.com/ceedaragents/cyrus/pull/837))
26+
- Redesigned TaskCreate formatting for parallel execution (concise `⏳ **subject**` checklist items), improved TaskUpdate/TaskGet to show subject names with status emojis, added ToolSearch formatting (`🔍 Loading`/`🔍 Searching tools`) rendered as non-ephemeral thought in AgentSessionManager, and added TaskOutput formatting (`📤 Waiting for`/`📤 Checking`). Updated both ClaudeMessageFormatter and GeminiMessageFormatter with matching logic. ([CYPACK-795](https://linear.app/ceedar/issue/CYPACK-795), [#846](https://github.com/ceedaragents/cyrus/pull/846))
27+
- Deferred TaskUpdate/TaskGet activity posting from tool_use time to tool_result time to enrich with task subject. Added `taskSubjectsByToolUseId` and `taskSubjectsById` caches to AgentSessionManager for subject resolution from TaskCreate results and TaskGet result parsing. ([CYPACK-797](https://linear.app/ceedar/issue/CYPACK-797), [#847](https://github.com/ceedaragents/cyrus/pull/847))
28+
29+
### Added
30+
- Subroutine result text is now stored in procedure history when advancing between subroutines. On error results (e.g. `error_max_turns` from single-turn subroutines), `AgentSessionManager` recovers by using the last completed subroutine's result via `ProcedureAnalyzer.getLastSubroutineResult()`, allowing the procedure to continue to completion instead of failing. Added `disallowAllTools` parameter to `buildAgentRunnerConfig` and `tools` config pass-through to `ClaudeRunner` for properly disabling built-in tools. ([CYPACK-792](https://linear.app/ceedar/issue/CYPACK-792), [#843](https://github.com/ceedaragents/cyrus/pull/843))
31+
32+
## [0.2.20] - 2026-02-05
33+
34+
(No internal changes in this release)
35+
1636
## [0.2.19] - 2026-01-24
1737

1838
### Fixed

CHANGELOG.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,86 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
### Added
8+
- GitHub PR comment support: Cyrus can now be triggered by `@cyrusagent` mentions on GitHub pull request comments, creating sessions and posting replies directly on PRs. ([CYPACK-772](https://linear.app/ceedar/issue/CYPACK-772), [#820](https://github.com/ceedaragents/cyrus/pull/820))
9+
10+
### Fixed
11+
- Summary subroutines now properly disable all tools including MCP tools like Linear's create_comment ([#808](https://github.com/ceedaragents/cyrus/pull/808))
12+
- Procedures no longer fail when a subroutine exits with an error (e.g., hitting the max turns limit). Cyrus now recovers by using the last successful subroutine's result, allowing the workflow to continue to completion instead of stopping mid-procedure ([#818](https://github.com/ceedaragents/cyrus/pull/818))
13+
14+
## [0.2.21] - 2026-02-09
15+
16+
### Changed
17+
- **Updated Claude SDK dependencies** - Updated `@anthropic-ai/claude-agent-sdk` to v0.2.34 and `@anthropic-ai/sdk` to v0.73.0. See [claude-agent-sdk changelog](https://github.com/anthropics/claude-agent-sdk-typescript/blob/main/CHANGELOG.md#v0234) for details. ([CYPACK-788](https://linear.app/ceedar/issue/CYPACK-788), [#837](https://github.com/ceedaragents/cyrus/pull/837))
18+
- **Improved task and tool activity display** - Task creation now shows as concise checklist items instead of verbose multi-line entries, task status updates display the task name with status emoji, and tool search/background task output activities are now cleanly formatted. ([CYPACK-795](https://linear.app/ceedar/issue/CYPACK-795), [#846](https://github.com/ceedaragents/cyrus/pull/846))
19+
- **Task status updates now show task descriptions** - Task update and task detail activities now display the task subject alongside the task number (e.g., "Task #3 — Fix login bug") instead of just the number. ([CYPACK-797](https://linear.app/ceedar/issue/CYPACK-797), [#847](https://github.com/ceedaragents/cyrus/pull/847))
20+
21+
### Fixed
22+
- **Procedures no longer fail when a subroutine exits with an error** - When a single-turn subroutine hits the max turns limit, Cyrus now recovers by using the last successful subroutine's result, allowing the workflow to continue to completion instead of stopping mid-procedure. ([CYPACK-792](https://linear.app/ceedar/issue/CYPACK-792), [#843](https://github.com/ceedaragents/cyrus/pull/843))
23+
24+
### Packages
25+
26+
#### cyrus-cloudflare-tunnel-client
27+
- cyrus-cloudflare-tunnel-client@0.2.21
28+
29+
#### cyrus-config-updater
30+
- cyrus-config-updater@0.2.21
31+
32+
#### cyrus-linear-event-transport
33+
- cyrus-linear-event-transport@0.2.21
34+
35+
#### cyrus-claude-runner
36+
- cyrus-claude-runner@0.2.21
37+
38+
#### cyrus-core
39+
- cyrus-core@0.2.21
40+
41+
#### cyrus-simple-agent-runner
42+
- cyrus-simple-agent-runner@0.2.21
43+
44+
#### cyrus-gemini-runner
45+
- cyrus-gemini-runner@0.2.21
46+
47+
#### cyrus-edge-worker
48+
- cyrus-edge-worker@0.2.21
49+
50+
#### cyrus-ai (CLI)
51+
- cyrus-ai@0.2.21
52+
53+
## [0.2.20] - 2026-02-05
54+
55+
### Fixed
56+
- **Agent guidance for draft PRs now respected** - When your Linear workspace guidance specifies `--draft` or requests PRs remain as drafts, Cyrus will no longer automatically convert them to ready for review. PRs also now correctly target the configured base branch instead of defaulting to main. ([CYPACK-784](https://linear.app/ceedar/issue/CYPACK-784), [#834](https://github.com/ceedaragents/cyrus/pull/834))
57+
58+
### Packages
59+
60+
#### cyrus-cloudflare-tunnel-client
61+
- cyrus-cloudflare-tunnel-client@0.2.20
62+
63+
#### cyrus-config-updater
64+
- cyrus-config-updater@0.2.20
65+
66+
#### cyrus-linear-event-transport
67+
- cyrus-linear-event-transport@0.2.20
68+
69+
#### cyrus-claude-runner
70+
- cyrus-claude-runner@0.2.20
71+
72+
#### cyrus-core
73+
- cyrus-core@0.2.20
74+
75+
#### cyrus-simple-agent-runner
76+
- cyrus-simple-agent-runner@0.2.20
77+
78+
#### cyrus-gemini-runner
79+
- cyrus-gemini-runner@0.2.20
80+
81+
#### cyrus-edge-worker
82+
- cyrus-edge-worker@0.2.20
83+
84+
#### cyrus-ai (CLI)
85+
- cyrus-ai@0.2.20
86+
787
## [0.2.19] - 2026-01-24
888

989
### Fixed

apps/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cyrus-ai",
3-
"version": "0.2.19",
3+
"version": "0.2.21",
44
"description": "AI-powered Linear issue automation using Claude",
55
"main": "dist/src/app.js",
66
"types": "dist/src/app.d.ts",

apps/cli/src/services/Logger.ts

Lines changed: 40 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,80 @@
1-
/**
2-
* Log levels in order of severity
3-
*/
4-
export enum LogLevel {
5-
DEBUG = 0,
6-
INFO = 1,
7-
SUCCESS = 2,
8-
WARN = 3,
9-
ERROR = 4,
10-
SILENT = 5,
11-
}
1+
import {
2+
createLogger,
3+
type ILogger,
4+
type LogContext,
5+
type LogLevel,
6+
} from "cyrus-core";
7+
8+
// Re-export LogLevel from cyrus-core so existing consumers don't break
9+
export { LogLevel } from "cyrus-core";
1210

1311
/**
1412
* Logger configuration options
1513
*/
1614
export interface LoggerOptions {
1715
/** Minimum log level to output */
1816
level?: LogLevel;
19-
/** Prefix to add to all log messages */
17+
/** Prefix to add to all log messages (used as component name) */
2018
prefix?: string;
2119
/** Whether to include timestamps */
2220
timestamps?: boolean;
2321
}
2422

2523
/**
26-
* Simple, zero-dependency logger service with structured logging
24+
* CLI-specific logger that wraps the core ILogger.
25+
*
26+
* Provides CLI-presentation features (emoji formatting, raw output,
27+
* dividers, child loggers) on top of the standard core logging interface.
28+
*
29+
* Implements ILogger so it can be passed to packages that expect the core interface.
2730
*/
28-
export class Logger {
29-
private level: LogLevel;
31+
export class Logger implements ILogger {
32+
private coreLogger: ILogger;
3033
private prefix: string;
3134
private timestamps: boolean;
3235

3336
constructor(options: LoggerOptions = {}) {
34-
this.level = options.level ?? this.getLogLevelFromEnv();
3537
this.prefix = options.prefix ?? "";
3638
this.timestamps = options.timestamps ?? false;
37-
}
38-
39-
/**
40-
* Get log level from environment variable
41-
*/
42-
private getLogLevelFromEnv(): LogLevel {
43-
const envLevel = process.env.CYRUS_LOG_LEVEL?.toUpperCase();
44-
switch (envLevel) {
45-
case "DEBUG":
46-
return LogLevel.DEBUG;
47-
case "INFO":
48-
return LogLevel.INFO;
49-
case "SUCCESS":
50-
return LogLevel.SUCCESS;
51-
case "WARN":
52-
return LogLevel.WARN;
53-
case "ERROR":
54-
return LogLevel.ERROR;
55-
case "SILENT":
56-
return LogLevel.SILENT;
57-
default:
58-
return LogLevel.INFO;
59-
}
60-
}
61-
62-
/**
63-
* Format a log message with optional prefix and timestamp
64-
*/
65-
private format(message: string): string {
66-
let formatted = message;
67-
68-
if (this.prefix) {
69-
formatted = `[${this.prefix}] ${formatted}`;
70-
}
71-
72-
if (this.timestamps) {
73-
const timestamp = new Date().toISOString();
74-
formatted = `${timestamp} ${formatted}`;
75-
}
76-
77-
return formatted;
78-
}
79-
80-
/**
81-
* Check if a log level should be output
82-
*/
83-
private shouldLog(level: LogLevel): boolean {
84-
return level >= this.level;
39+
this.coreLogger = createLogger({
40+
component: this.prefix || "CLI",
41+
level: options.level,
42+
});
8543
}
8644

8745
/**
8846
* Debug log (lowest priority)
8947
*/
9048
debug(message: string, ...args: any[]): void {
91-
if (this.shouldLog(LogLevel.DEBUG)) {
92-
console.log(this.format(`🔍 ${message}`), ...args);
93-
}
49+
this.coreLogger.debug(message, ...args);
9450
}
9551

9652
/**
9753
* Info log (normal priority)
9854
*/
9955
info(message: string, ...args: any[]): void {
100-
if (this.shouldLog(LogLevel.INFO)) {
101-
console.log(this.format(message), ...args);
102-
}
56+
this.coreLogger.info(message, ...args);
10357
}
10458

10559
/**
106-
* Success log (positive outcome)
60+
* Success log - maps to info level with check mark prefix
10761
*/
10862
success(message: string, ...args: any[]): void {
109-
if (this.shouldLog(LogLevel.SUCCESS)) {
110-
console.log(this.format(`✅ ${message}`), ...args);
111-
}
63+
this.coreLogger.info(message, ...args);
11264
}
11365

11466
/**
11567
* Warning log
11668
*/
11769
warn(message: string, ...args: any[]): void {
118-
if (this.shouldLog(LogLevel.WARN)) {
119-
console.warn(this.format(`⚠️ ${message}`), ...args);
120-
}
70+
this.coreLogger.warn(message, ...args);
12171
}
12272

12373
/**
12474
* Error log (highest priority)
12575
*/
12676
error(message: string, ...args: any[]): void {
127-
if (this.shouldLog(LogLevel.ERROR)) {
128-
console.error(this.format(`❌ ${message}`), ...args);
129-
}
77+
this.coreLogger.error(message, ...args);
13078
}
13179

13280
/**
@@ -141,7 +89,7 @@ export class Logger {
14189
*/
14290
child(prefix: string): Logger {
14391
return new Logger({
144-
level: this.level,
92+
level: this.coreLogger.getLevel(),
14593
prefix: this.prefix ? `${this.prefix}:${prefix}` : prefix,
14694
timestamps: this.timestamps,
14795
});
@@ -151,21 +99,29 @@ export class Logger {
15199
* Print a divider line
152100
*/
153101
divider(length = 70): void {
154-
this.raw("─".repeat(length));
102+
this.raw("\u2500".repeat(length));
103+
}
104+
105+
/**
106+
* Create a new logger with additional context.
107+
* Delegates to the core logger's withContext.
108+
*/
109+
withContext(context: LogContext): ILogger {
110+
return this.coreLogger.withContext(context);
155111
}
156112

157113
/**
158114
* Set log level dynamically
159115
*/
160116
setLevel(level: LogLevel): void {
161-
this.level = level;
117+
this.coreLogger.setLevel(level);
162118
}
163119

164120
/**
165121
* Get current log level
166122
*/
167123
getLevel(): LogLevel {
168-
return this.level;
124+
return this.coreLogger.getLevel();
169125
}
170126
}
171127

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/claude-runner/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cyrus-claude-runner",
3-
"version": "0.2.19",
3+
"version": "0.2.21",
44
"description": "Claude CLI execution wrapper for Cyrus",
55
"type": "module",
66
"main": "dist/index.js",
@@ -16,8 +16,8 @@
1616
"typecheck": "tsc --noEmit"
1717
},
1818
"dependencies": {
19-
"@anthropic-ai/claude-agent-sdk": "^0.2.7",
20-
"@anthropic-ai/sdk": "^0.71.2",
19+
"@anthropic-ai/claude-agent-sdk": "^0.2.34",
20+
"@anthropic-ai/sdk": "^0.73.0",
2121
"@linear/sdk": "^64.0.0",
2222
"cyrus-core": "workspace:*",
2323
"dotenv": "^16.4.5",

0 commit comments

Comments
 (0)