Merged
Conversation
…cts (#998) Co-authored-by: Cascade Bot <bot@cascade.dev>
…/factories.ts (#999) Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…c interface (#1001) Introduces Sentry as the first alerting provider under a new 'alerting' integration category, using provider-agnostic naming throughout so that adding a second provider (PagerDuty, Datadog, etc.) requires no prompt or interface changes. ## Provider-agnostic naming (the PM analogy) Like how Trello "card" + JIRA "issue" are abstracted to "work item" in the PM category, Sentry-specific language is hidden behind the alerting namespace at every agent-facing layer: - AgentInput fields: `alertIssueId`, `alertOrgId`, `alertIssueUrl` - Gadgets: `GetAlertingIssue`, `GetAlertingEventDetail`, `ListAlertingEvents` - CLI tools: `get-alerting-issue`, `get-alerting-event`, `list-alerting-events` - Context step: `alertingIssue` (was `sentryIssue`) - Agent YAML prompts: no Sentry-specific language Sentry internals (client, types, HMAC verification) remain Sentry-named as the abstraction boundary stops at the agent-facing interface. ## New capabilities - `alerting:read` capability with all three gadgets (GetAlertingIssue, GetAlertingEventDetail, ListAlertingEvents) — ListAlertingEvents was previously missing despite having a CLI tool and core function - Sentry webhook handler via `createWebhookHandler` factory, gaining webhook logging to `webhook_logs` and opt-in HMAC-SHA256 signature verification (`Sentry-Hook-Signature` header, raw hex format) - `verifySentrySignature` in signatureVerification.ts (timing-safe) - `verifySentryWebhookSignature` in webhookVerification.ts reads `webhook_secret` from the alerting integration credential ## Fixes - `formatSentryEvent` cognitive complexity reduced from 34 to ~8 by extracting five section helpers (appendEventMeta, appendEventTags, appendEventRequest, appendEventUser, appendEventStacktrace) - Removed dead `_client` caching variable from sentry/client.ts - Removed Sentry branding from formatted output strings ## Tests - 41 new/updated tests: verifySentrySignature (9), SentryIssueAlertTrigger (15), SentryMetricAlertTrigger (12), builtins registration (1 new + mock) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…1002) Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…r factory (#1007) Co-authored-by: Cascade Bot <bot@cascade.dev>
…outer adapter (#1008) Co-authored-by: Cascade Bot <bot@cascade.dev>
…grations, reduce duplication (#1009) Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…y DI (#1012) Co-authored-by: Cascade Bot <bot@cascade.dev>
* feat(dashboard): redesign LLM Calls tab with activity visibility
Add a rich Activity column to the LLM Calls table so users can see
what each call was doing at a glance — without expanding every row.
**Parser layer (new)**
- Add `src/utils/llmResponseParser.ts` and frontend twin
`web/src/lib/llm-response-parser.ts` that normalize all four engine
response formats (Claude Code/OpenCode JSON arrays, Codex JSON object,
LLMist gadget markup, raw text fallback) into a canonical
`ParsedLlmResponse` with `blocks[]`, `toolNames[]`, and `textPreview`.
- `toolNames` carries one entry per invocation (NOT deduplicated) so
×N badge counts reflect actual call frequency.
- `summarizeInput` extracts human-readable summaries for well-known tools
(Read/Write/Edit → file_path, Bash → command, Glob/Grep → pattern, etc.)
with consistent 100-char truncation.
- Internal helpers (`flushGadgetArg`, `finalizeGadget`, `handleGadgetStart`,
`processLlmistLine`, `processClaudeBlock`) extracted to module scope so
each function stays under the cognitive complexity limit.
**API layer**
- `listLlmCallsMeta` now selects `response` alongside token/cost metadata.
- `listLlmCalls` router runs the parser server-side and returns `toolNames`
+ `textPreview` per call; raw `response` payloads are NOT forwarded to
the client.
**UI — list view**
- New Activity column: colored tool-name badges (sky=read, amber=bash,
emerald=write, violet=web/agent) with ×N counts + truncated text preview.
- `getToolStyle` extracted to `web/src/lib/tool-style.ts` (was duplicated
in two components).
- Inter-call Δ Time column computed from `createdAt` timestamps.
- Summary stat cards (Total Calls, Input Tokens, Output Tokens, Cached %).
- Row expansion uses `<Fragment key>` to avoid React key warnings.
- Keyboard-accessible rows (`tabIndex={0}`, Enter/Space toggles).
- `isError` guard added alongside the existing `isLoading` guard.
**UI — detail view**
- Structured blocks view: text (muted bg), tool_use (colored badge +
monospace inputSummary), thinking (collapsible `<details>`).
- "Raw" / "Structured" toggle; raw JSON parse is lazy (only runs when
the pane is shown).
- Metadata bar with model (font-mono), time, tokens, cached, cost.
- `buildMetaItems` extracted to reduce component complexity; `MetaItem`
type replaces fragile string-identity check for `font-mono`.
- `isError` guard added.
**Tests**
- New `tests/unit/utils/llmResponseParser.test.ts` covering all five
format branches (Claude Code, Codex, LLMist, fallback, empty/null)
plus edge cases (dedup, truncation, multi-line args, unknown blocks).
- New router test verifies `toolNames` and `textPreview` are extracted
from a real Claude Code response payload, not just from `null` responses.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(tests): update listLlmCallsMeta integration test for response field
The test asserted response was excluded from listLlmCallsMeta, but the
router now needs response to extract toolNames/textPreview server-side.
Update the test to reflect the new contract: request is still excluded,
response is now included.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…tests (#1013) Co-authored-by: Cascade Bot <bot@cascade.dev>
…sLifecycle, secretOrchestrator (#1014) Co-authored-by: Cascade Bot <bot@cascade.dev>
…ivity (#1015) Token counts in the LLM Calls tab were near-zero for Claude Code runs because only usage.input_tokens (the uncached portion) was recorded. With Anthropic prompt caching, the vast majority of tokens land in cache_read_input_tokens and cache_creation_input_tokens instead. Fix logClaudeCodeLlmCall: - inputTokens = input_tokens + cache_read_input_tokens + cache_creation_input_tokens - cachedTokens = cache_read_input_tokens (tokens served from cache) - costUsd computed via calculateCost() using toPricingKey() which converts 'claude-sonnet-4-5-20250929' → 'anthropic:claude-sonnet-4-5' for pricing lookup Also refactor processAssistantMessage to extract processContentBlock helper, reducing Biome cognitive complexity from 17 to under 15. LLM Calls tab activity column improvements: - listLlmCalls API now returns toolCalls [{name, inputSummary}] instead of flat toolNames [], surfacing the parsed input summary (file path, command, etc.) for each tool call without requiring row expansion - thinkingChars added: total chars across all thinking blocks shown inline as "thinking (N chars)" in muted italic - Each tool call rendered as [Badge] monospace-param inline in the list row Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…riven lifecycle hooks (#1016) Co-authored-by: Cascade Bot <bot@cascade.dev>
… thinking inline (#1017) - LlmCallDetail now defaults to raw JSON view (showRaw=true); structured view remains accessible via the toggle. Raw JSON is the unique content that isn't already visible in the list row, so it should be the default. - Remove redundant metadata bar from detail panel (model/tokens/cost/time are already shown in the list columns). - listLlmCalls API now also returns thinkingPreview (first 200 chars of thinking text, concatenated across blocks) alongside thinkingChars. - List row Activity column shows the actual thinking text truncated, with char count suffix when the full text exceeds 200 chars, instead of just "thinking (N chars)". Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…ss engines (#1019) * feat(backends): add NativeToolEngine abstract base class for subprocess engines * docs(backends): fix NativeToolEngine class-level JSDoc inaccuracies Remove the erroneous bullet about buildSystemPrompt/buildTaskPrompt (those functions are standalone imports used by each engine's own execute(), not a base class responsibility). Also correct the abstract method name from executeTurn() to execute() to match the actual contract. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Cascade Bot <bot@cascade.dev> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…rationRegistry (#1021) Co-authored-by: Cascade Bot <bot@cascade.dev>
… providers in unified registry (#1022) Co-authored-by: Cascade Bot <bot@cascade.dev>
…ine directly (#1023) Co-authored-by: Cascade Bot <bot@cascade.dev>
* feat(sentry): add worker-side Sentry webhook job dispatch * fix(sentry): use pre-computed triggerResult and run agent in processSentryWebhook - Short-circuit registry.dispatch when triggerResult is already provided, matching the router→worker contract followed by Trello, JIRA, and GitHub handlers - After resolving the trigger result, call runAgentExecutionPipeline to actually execute the matched agent (fixes silent discard of matched triggers) - Fix SentryJobData JSDoc comment: add 'issue' to eventType union to match router-side SentryJob type in src/router/queue.ts - Update tests: assert registry.dispatch is NOT called when triggerResult is provided; add coverage for agent execution pipeline call Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Cascade Bot <bot@cascade.dev> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…roles (#1025) Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…tion class (#1027) Co-authored-by: Cascade Bot <bot@cascade.dev>
…re already merged (#1028) ## Root cause The backlog-manager declared the backlog blocked in two situations: 1. **LLM matching failure**: haiku couldn't match a short dependency reference ("SCMIntegration") in a backlog card's description to the full user-story title in the MERGED list ("As a developer, I want SCMIntegration and GitHubSCMIntegration…"). Stale "(not yet merged)" annotations in descriptions further anchored it toward "blocked". 2. **Missing re-trigger**: when blocking dependency cards were manually moved to MERGED in Trello (outside CASCADE's PR flow), no trigger fired, leaving the backlog incorrectly blocked indefinitely. ## Changes **Prompt improvements** (`backlog-manager.eta`): - Add explicit warning that "(not yet merged)" text is always stale — the MERGED list is the only source of truth - Replace vague MERGED-check guidance with concrete substring/keyword matching instructions: if the dependency name appears anywhere in a MERGED title it is resolved - Scope the conservative rule: be conservative when *detecting* dependencies, but generous when *resolving* them against MERGED **Pipeline snapshot** (`contextSteps.ts`): - Include URL in parentheses for DONE/MERGED items so the agent can do exact URL matching when descriptions reference PM links - Guard against empty URL (render nothing rather than empty `()`) **New trigger** (`status-changed.ts`, `register.ts`): - Add `TrelloStatusChangedMergedTrigger`: re-triggers backlog-manager whenever any card is moved to the MERGED list, catching manually resolved dependencies that would otherwise leave the backlog stuck **Agent definition** (`backlog-manager.yaml`): - Remove misleading `targetStatus` parameter that implied independent control over backlog vs. merged firing (both always fire when enabled) - Update label and description to accurately describe dual-list behaviour **Tests**: - Add `merged-status-changed.test.ts` with full parallel coverage to `backlog-status-changed.test.ts` (matches, non-matches, disabled trigger, handle result) - Update pipeline snapshot test: rename "title-only" → "title-and-url", assert URL present, add empty-URL edge-case test - Add missing `triggerEvent` assertion to backlog trigger test Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… static schema pre-registration (#1029) Co-authored-by: Cascade Bot <bot@cascade.dev>
…rray (#1031) GitHub fires check_suite webhooks with pull_requests: [] when CI runs on the refs/pull/{N}/head virtual ref rather than the named feature branch. The CheckSuiteFailureTrigger's matches() guard silently rejected these, so respond-to-ci never fired even when CI failed on implementer PRs. Root cause confirmed via webhook log f0f88951 for PR #1030: conclusion was "failure", head_branch was "refs/pull/1030/head", pull_requests was []. Changes: - Extract parsePrNumberFromRef() to utils.ts (removes duplication between the two trigger files, adds JSDoc explaining the merge-ref exclusion) - Restrict the regex to refs/pull/{N}/head only — the /merge variant uses a synthetic merge-commit SHA that is not part of the PR branch history - Update matches() in both CheckSuiteFailureTrigger and CheckSuiteSuccessTrigger to accept events where pull_requests is empty but head_branch parses as a PR ref - Simplify prBranch resolution to always use prDetails.headRef (already fetched) instead of a conditional that picked the same value either way - Fix head_branch type to string | null (GitHub sends null, not undefined, when the check suite is not associated with a named branch) - Add respond-to-ci trigger example to docs/getting-started.md Tests: - New unit tests for the empty pull_requests + refs/pull/{N}/head path in both trigger test files (matches and handle coverage) - New describe('parsePrNumberFromRef') block in github-utils.test.ts covering null/undefined/empty, plain branches, /merge rejection, valid /head refs, and partial-match rejection Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
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
Merges 34 commits from
devintomain. Key changes:Bug fixes
respond-to-cinot triggering when GitHub sendscheck_suitewithpull_requests: []onrefs/pull/{N}/headvirtual ref (fix(triggers): handle check_suite webhooks with empty pull_requests array #1031)SELF_SIGNED_CERT_IN_CHAINin production migration containers (fix(deploy): fix SELF_SIGNED_CERT_IN_CHAIN in production migration containers #996)Backend / engine architecture
NativeToolEngineabstract base class for subprocess engines (feat(backends): add NativeToolEngine abstract base class for subprocess engines #1019)NativeToolEnginefromClaudeCodeEngine(refactor(backends): extend NativeToolEngine from ClaudeCodeEngine #1020); Codex (feat(codex): extend NativeToolEngine instead of implementing AgentEngine directly #1023) and OpenCode (feat(opencode): extend NativeToolEngine in OpenCodeEngine #1026) extend it tooresolveSettings()inNativeToolEngine, remove static schema pre-registration (feat(backends): unified resolveSettings() in NativeToolEngine, remove static schema pre-registration #1029)archetypefield toAgentEngineDefinition(feat(backends): add archetype field to AgentEngineDefinition #1018)Integrations
IntegrationModuleinterface andIntegrationRegistry(feat(integrations): add unified IntegrationModule interface and IntegrationRegistry #1021)SCMIntegrationinterface andGitHubSCMIntegrationclass (feat(integrations): add SCMIntegration interface and GitHubSCMIntegration class #1027)PMIntegrationfromIntegrationModule, register PM providers in unified registry (feat(pm): extend PMIntegration from IntegrationModule and register PM providers in unified registry #1022)Dashboard / UX
Refactoring
agentTypebranching (feat(lifecycle): replace hardcoded agentType branching with profile-driven lifecycle hooks #1016)adapter.tsintosidecarManager,progressLifecycle,secretOrchestrator(refactor(backends): decompose adapter.ts into sidecarManager, progressLifecycle, secretOrchestrator #1014)DatabaseContextpattern for injectable DB in tests (refactor(db): introduce DatabaseContext pattern for injectable db in tests #1013)CredentialResolverinterface for test-friendly DI (feat(config): introduce CredentialResolver interface for test-friendly DI #1012)SessionStateinto injectable class (refactor(session): extract SessionState into injectable class #1010)verifyHmachelper andcreateWebhookVerifierfactory (refactor(webhook): extract verifyHmac helper and createWebhookVerifier factory #1007)Tests & docs
CLAUDE.mdand addtests/README.md(docs(tests): add tests/README.md with factory and mock catalogs #1006, docs: streamline CLAUDE.md — fix stale info, add missing engines/integrations, reduce duplication #1009)respond-to-citrigger example todocs/getting-started.md🤖 Generated with Claude Code