Merge dev to main#615
Merged
zbigniewsobiecki merged 73 commits intomainfrom Mar 6, 2026
Merged
Conversation
chore: track squint local database
When the Claude Code backend passes checklist items as JSON objects
(e.g. --item '{"name":"...","description":"..."}'), the raw JSON string
was being used as the JIRA subtask title instead of the name field.
Add a parseItem() helper that tries JSON.parse on each --item value and
returns a ChecklistItemInput object when the result has a string `name`
property. Plain strings and unrecognised JSON fall back to the raw string,
preserving full backward compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lists When a card in IN PROGRESS, IN REVIEW, DONE or any other non-trigger list received the READY TO PROCESS label, the handler fell through to a hardcoded default of 'splitting', firing an unintended splitting run. Replace the fallback with an early null return so the trigger is silently skipped for any list that isn't splitting/planning/todo. Update the unit test to assert null instead of the previous incorrect expectation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…son-parsing fix(cli): parse JSON --item strings in add-checklist CLI command
Remove unused `eq`, `getDb`, and `organizations` imports from repositories-edge-cases.test.ts. Extract duplicated `assertFound<T>()` helper from 3 test files into tests/integration/helpers/assert.ts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…recognized-list fix(triggers): skip READY TO PROCESS label for cards in non-eligible lists
Remove ~70% duplicated test surface from webhook-logging.test.ts and multi-provider-credentials.test.ts that overlapped with existing webhookLogsRepository.test.ts, credentialsRepository.test.ts, and credentialResolution.test.ts. Kept only the unique value-add tests: - webhook-logging: per-source GitHub/JIRA logs, bodyRaw, project resolution - multi-provider-credentials: multi-project isolation, PM/SCM isolation, dual-persona tokens, 3-project cross-contamination checks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… for proper table support
…ercise createPMProvider - Replace if/else conditional assertions in github-personas and pm-provider-switching tests with direct expect() calls that fail if behavior changes (addresses review observation #3) - Replace manual pm.type ?? 'trello' reimplementation with actual createPMProvider() call in "defaults to Trello" test (addresses review observation #2) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…support fix(jira): replace hand-rolled markdownToAdf with marklassian library for proper table support
…ts-699f2e4 feat(tests): add integration tests for triggers, webhooks, credentials, and personas
…r-from-messages feat(progress): remove visual progress bars and iteration counters from messages
Implement comprehensive email integration for CASCADE agents: Core features: - IMAP client for searching, reading emails (imapflow) - SMTP client for sending emails, replying to threads (nodemailer) - AsyncLocalStorage-based credential scoping (withEmailIntegration) - Database migration for email integration credentials Gadgets (SearchEmails, ReadEmail, SendEmail, ReplyToEmail): - Full schema validation (RFC 2822 subject length, date formats, UID validation) - Error logging for all gadget operations - HTML body fallback when text body unavailable - Proper email threading support (In-Reply-To, References headers) Agent execution integration: - Email credential scoping in manual-runner, GitHub webhook handler, PM webhook handler - Integration role definitions for email provider credentials - canAccessEmail capability flag in agent definitions Improvements from code review: - IMAP connection timeouts (30s connect, 15s greeting, 60s socket) - Awaited transport.close() to prevent connection leaks - Credential resolution error logging - Reduced cognitive complexity via helper function extraction Tests: - Email integration tests (credential resolution, withEmailIntegration) - Email client credential scoping tests - Gadget core function tests (27 tests total) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(email): add email client tools for agents
…561) ## Email-Joke Agent - New agent type for responding to emails with humorous replies - Agent definition in YAML with prompts and gadget configuration - Reads unread emails, sends joke replies, marks as read ## Email Integration - Gmail OAuth support with browser-based authentication flow - IMAP/SMTP support for any email provider - Credential management per integration role (imap_host, smtp_port, etc.) - Email wizard UI for setup with multi-step flow - CLI commands: email integration-set, joke-config, oauth, verify ## Database Schema - Migration 0018: Gmail OAuth token storage - Migration 0019: Make repo column optional (for email-only projects) - Updated ProjectConfigRaw and ProjectRow types ## UI Improvements - Email wizard component with Gmail OAuth and IMAP configuration - OAuth callback route for Gmail authentication - Project forms now support optional repo field - EmailJokeConfig component for sender email filtering ## Code Quality Fixes - Added error handling to markEmailAsSeen() in email client - Fixed duplicate comment in email/client.ts - Added parseEmailJokeTriggers() helper with proper type safety - Updated triggerConfig schema to allow null senderEmail - Added guards for email-only projects in setup-webhooks tool - Refactored CLI joke-config to reduce cognitive complexity ## Tests - Added tests for EmailJokeTriggerConfigSchema - Added tests for parseEmailJokeTriggers and resolveEmailJokeTriggerConfig - Added tests for markEmailAsSeen gadget function Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…#562) Add pre-flight validation of project integrations before agent execution. This catches misconfiguration early with clear, actionable error messages pointing users to the dashboard settings. Key changes: - Add validateIntegrations() to check PM, SCM, and email integrations - Add persona-aware SCM validation (implementer vs reviewer tokens) - Add hasEmailIntegration(), hasPmIntegration(), hasScmIntegration() checks - Add persona field to agent definitions for SCM token requirements - Wire validation into agent-execution and manual-runner entry points Agent requirements by type: - implementation, splitting, planning: PM + SCM (implementer) - respond-to-review, respond-to-ci, respond-to-pr-comment: SCM (implementer) - review: SCM (reviewer) - debug: PM only - email-joke: email only Test improvements: - Add comprehensive integration tests (45 tests) - Add unit tests for validation logic (10 tests) - Refactor implementer agent tests using it.each() - Standardize seedGitHubIntegration helper options to skip* pattern - Add Gmail credential tests and empty value edge case - Add consistent array length checks before element access Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…crash (#563) `cascade email verify` was crashing with a Zod `invalid_string` error because the CLI passed the masked credential value (`****xyz`) returned by `credentials.list` directly as the `email: z.string().email()` field on the `verifyGmail` mutation. Fix: replace `email: z.string().email()` with `gmailEmailCredentialId: z.number()` in the `verifyGmail` input schema, resolve the email server-side via `resolveCredentialValue()` (consistent with `verifyImap` and every other credential in this router), and remove the now-redundant client-side credential value lookup from the CLI. Also adds tests for `verifyGmail` (auth, success, schema guard, token refresh failure, IMAP failure) and `verifyImap` (auth, success, invalid port, IMAP failure) — neither procedure had test coverage before. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…isting Gmail integration (#564) When opening the email wizard in edit mode for an existing Gmail integration, INIT_EDIT set oauthComplete=true but left gmailEmail and verificationEmail as null. This caused two problems: 1. Clicking "Confirm" dispatched SET_VERIFICATION with email: null (state.gmailEmail), so verificationEmail stayed null and the "Update Integration" button remained disabled. 2. The verify step showed "Gmail connection verified for " (empty name). Fix: in the INIT_EDIT useEffect, wait for orgCredentials to load then look up the gmail_email credential (stored as "Gmail: user@example.com") and pre-populate both gmailEmail and verificationEmail. This auto-confirms the verify step for existing integrations so "Update Integration" is immediately enabled, consistent with how IMAP edit mode works. Uses a useRef guard to ensure INIT_EDIT only fires once even though orgCredentials is now a dependency. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The EmailJokeConfig component (sender filter for the email-joke agent) was exported from email-wizard.tsx but never mounted anywhere in the UI. Add it below the EmailWizard in the email integration tab so users can configure the sender email filter from the dashboard. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Cascade Bot <bot@cascade.dev> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…567) The EmailJokeConfig sender filter widget was placed in the Email integration tab, but it is agent-specific trigger configuration and belongs in the Agent Configs tab alongside PM and SCM triggers. Changes: - Add 'email-joke' to ALL_AGENT_TYPES so it appears as a section in Agent Configs - Move AGENT_LABELS to trigger-agent-mapping.ts and type it as Record<KnownAgentType, string> — adding a new agent type without a label is now a compile error rather than a silent fallback - Export EMAIL_TRIGGER_AGENTS (Set<KnownAgentType>) from trigger-agent-mapping.ts — replaces the magic string 'email-joke' that was hard-coded in the generic AgentSection component - Add 'email-joke': [] to AGENT_TRIGGER_MAP for consistency with all other known agent types - Render EmailJokeConfig inside the email-joke AgentSection under an "Email Triggers" heading when expanded - Remove EmailJokeConfig from the integration-form email tab - Remove "Add Custom Agent Config" button — only supported agent types defined in ALL_AGENT_TYPES are valid; per-section "Add Config" buttons pre-seed the type so it is always read-only in the dialog - Suppress pre-existing noExcessiveCognitiveComplexity biome warning in EmailWizard's multi-provider initialization useEffect - Add tests for AGENT_LABELS, EMAIL_TRIGGER_AGENTS, ALL_AGENT_TYPES completeness, and email-joke trigger definitions Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ds (#569) The three CLI integration-credential commands (list, set, remove) hardcoded `options: ['pm', 'scm']`, actively rejecting `--category email` even though the tRPC API already accepts all three categories. Users with email integrations had no CLI path to inspect or manage linked credentials. Changes: - `projects/overrides.ts`: add 'email' to category options; default sweep now includes pm + scm + email - `projects/override-set.ts`: add 'email' to category options and type cast - `projects/override-rm.ts`: add 'email' to category options and type cast - `email/integration-set.ts`: fix IMAP guidance note to include `--category email` so users land on the right command Also fix pre-existing `noExcessiveCognitiveComplexity` lint warning in `agent-execution.ts` by extracting the validation failure handling block into a `notifyValidationFailure` helper (complexity 17 → 12). Tests: - New `tests/unit/cli/dashboard/projects/integration-credentials.test.ts` covers all three categories for list/set/remove, plus rejection of unknown values and JSON output - New `tests/unit/cli/dashboard/email/integration-set.test.ts` covers gmail/imap upsert, custom config JSON, and the IMAP credential guidance - Extended `tests/unit/api/routers/projects.test.ts` with email category cases for all three integrationCredentials router procedures Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
SMTP port 465 is blocked in the worker container, causing all ReplyToEmail/SendEmail gadget calls on Gmail OAuth accounts to silently hang for 30 s before the gadget timeout fires — confirmed in the car-dealership email-joke run (three ReplyToEmail calls, each 30 000 ms). Root cause: nodemailer's createTransport() has no connection-level timeout, so the gadget outer timer was the only kill-switch, yielding a cryptic "Gadget exceeded timeout" error with no actionable detail. Fix: for OAuth accounts (authMethod === 'oauth'), route sendEmail() and replyToEmail() through the Gmail REST API (messages.send) instead of SMTP. IMAP operations (SearchEmails, ReadEmail, MarkEmailAsSeen) are unchanged — port 993 is not blocked. Implementation: - src/email/gmail/send.ts (new): sendViaGmailApi() and replyViaGmailApi() use nodemailer streamTransport (in-process, no network) to build RFC 822 bytes, then POST to gmail.users.messages.send via @googleapis/gmail. OAuth2Client passes the existing access token directly — no re-auth needed (token refresh is already handled in oauth.ts before this point). - src/email/client.ts: branch on creds.authMethod at the top of both send functions; password/SMTP accounts are completely unaffected. - @googleapis/gmail added as a production dependency (~1 MB, pulls in google-auth-library transitively). Tests: 8 new unit tests in tests/unit/email/gmail/send.test.ts covering success paths, base64url encoding, reply-to-sender, reply-all (self excluded), Re: prefix deduplication, and error propagation. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… fixes (#573) * refactor(email): replace monolithic client with registry-pattern provider architecture Decomposes EmailClient into clean, extensible layers: - EmailProvider interface — runtime ops (search/read/send/reply/mark) - EmailIntegration interface — credential resolution + AsyncLocalStorage scoping - EmailIntegrationRegistry — singleton, populated at import time (mirrors pm/index.ts) - ImapEmailProvider — password-auth via imapflow + nodemailer SMTP - GmailEmailProvider — OAuth-auth via imapflow IMAP + Gmail REST API send - ImapIntegration / GmailIntegration — per-provider DB credential resolution Code-review fixes applied to gadget core files: - Hoist const message before logger.error (was extracted twice in all 5 files) - Add (no body) fallback in readEmail for attachment-only emails - Guard empty accepted list in sendEmail + replyToEmail (misleading success message) - Remove embedded \n from searchEmails header (caused double blank line in output) - Log logger.warn in ImapIntegration when IMAP/SMTP port parses as NaN New and expanded test coverage: - context.test.ts: AsyncLocalStorage scoping + getEmailProvider throws outside scope - imap/adapter.test.ts: readEmail (success + not-found) + replyToEmail (threading, cleanup) - gmail/adapter.test.ts: searchEmails + readEmail tests; mocks migrated to vi.hoisted() - integration.test.ts: registry delegation, credential fallback, warn path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(email): import from email/index.js to trigger provider registration Production callers of withEmailIntegration / hasEmailIntegration were importing directly from email/integration.js, which bypasses the side-effect registration in email/index.ts that populates the emailRegistry with ImapIntegration and GmailIntegration. Without the registry populated, emailRegistry.getOrNull() always returns null, causing withEmailIntegration to run without scoping a provider (email gadgets fail) and hasEmailIntegration to always return false. Fix: update the four production callers and the integration test to import from email/index.js (same pattern as PM callers importing from pm/index.js). Files changed: - src/triggers/shared/integration-validation.ts - src/triggers/shared/manual-runner.ts - src/triggers/github/webhook-handler.ts - src/pm/webhook-handler.ts - tests/integration/integration-validation.test.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion (#574) Before this change the email-joke agent always started regardless of whether any matching emails existed — if the INBOX was empty the agent would search, find nothing, and call Finish immediately, wasting a full agent run. This PR adds a pre-check phase: before the agent starts, the manual runner searches for unread emails (filtered by senderEmail when configured). If none are found the run is skipped cleanly; if emails are found they are injected into the agent's initial context via the new `prefetchedEmails` pipeline step, so the agent can skip the redundant SearchEmails call and go straight to reading and replying. Changes: - src/types/index.ts: add `preFoundEmails?: EmailSummary[]` to AgentInput - src/triggers/shared/manual-runner.ts: add `prefetchEmailsForJokeAgent` pre-check inside withEmailIntegration; fix no-provider path to abort (return false) instead of silently proceeding with a broken prompt - src/agents/definitions/contextSteps.ts: add `fetchEmailsFromInputStep` that injects pre-fetched emails as a synthetic SearchEmails tool result - src/agents/definitions/schema.ts: register `prefetchedEmails` enum value - src/agents/definitions/strategies.ts: wire `prefetchedEmails` registry key - src/agents/definitions/email-joke.yaml: use `prefetchedEmails` pipeline step - src/agents/prompts/task-templates/emailJoke.eta: update task prompt to reference the pre-fetched results and drop the now-redundant search step Code-review fixes applied in the same commit: - Consolidate EmailSearchCriteria import to email barrel (email/index.js) - Remove redundant `as EmailSummary[]` and `as string` casts now that AgentInput has properly typed named fields - Registry key follows the existing noun-phrase convention (`prefetchedEmails` not `fetchEmailsFromInput`) Tests: - tests/unit/triggers/manual-runner.test.ts: new `email-joke pre-check` describe block (5 cases: no provider, zero emails, emails found, non-email agent skips pre-check, senderEmail → criteria.from filter) - tests/unit/agents/definitions/contextSteps.test.ts: new file with 6 focused tests for fetchEmailsFromInputStep (undefined/empty, injection shape, senderEmail filter, multi-email numbering, UTC date extraction) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…rganisation (#575) Three robustness fixes for the email-joke scheduler: 1. **Double-start guard** — `startEmailScheduler()` now mirrors `startWorkerProcessor()`: a second call logs a warning and returns early instead of creating a second concurrent `setInterval` loop. 2. **Deduplicating jobId** — `submitDashboardJob` accepts an optional `jobId` parameter (existing callers unchanged). The scheduler passes a deterministic `email-joke-{projectId}-{windowId}` ID so BullMQ silently rejects a duplicate job that arrives within the same interval window (prevents double-sends when a prior run is still in flight). 3. **Repository organisation** — `getAllProjectIdsWithEmailIntegration` moved into the existing `// Project Integrations` section of `settingsRepository.ts` (after `deleteProjectIntegration`, before `// Integration Credentials`), removing the stray `// Email Integration Queries` section it had been placed in. Also fixes a trailing-newline lint error in `settingsRepository.ts`. Tests: 13 new tests in `email-scheduler.test.ts`; 2 new cases in `settingsRepository.test.ts`; 1 new case in `config.test.ts`. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds end-to-end SMS support via Twilio, following the same registry/AsyncLocalStorage/credential-resolution patterns as the email integration. ## Backend - `src/sms/` — provider interface, registry, AsyncLocalStorage scoping, integration credential resolution, and Twilio adapter - `src/gadgets/sms/SendSms` — LLMist gadget that agents call to send SMS - `src/router/adapters/twilio.ts` — inbound webhook handler with Twilio signature validation (`POST /twilio/webhook/:projectId`) - SMS provider scoped in all three agent execution paths: pm/webhook-handler, github/webhook-handler, manual-runner - Pre-execution integration validation for agents that declare `sms` as a required integration ## Database - Migration 0020: extends `chk_integration_category_provider` to include `sms/twilio`, and `chk_integration_credential_role` to include `account_sid`, `auth_token`, `phone_number` - `getAllProjectIdsWithSmsIntegration()` in settingsRepository (mirrors email equivalent, ready for future SMS scheduler) ## API / CLI - `integrationsDiscovery.verifyTwilio` tRPC mutation — validates Account SID + Auth Token against the Twilio API - `projects.integrations.*` and `integrationCredentials.*` routers updated to accept `sms` category - CLI `integration-credentials`, `integration-credential-set`, `integration-credential-rm` commands updated to include `sms` ## Dashboard UI - `TwilioWizard` — 3-step accordion (credentials → verify → save) with inline credential creator, copy-to-clipboard webhook URL panel, and edit-mode pre-verification - `IntegrationForm` — new SMS tab wired to TwilioWizard ## Tests - Unit tests for SMS context, TwilioSmsProvider, TwilioIntegration, webhook handler, SendSms gadget, settingsRepository, and CLI commands - 206 test files, all passing Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The `npm run build` script was missing a step to copy system prompt templates, causing blank System Prompt tabs in the Agent Definition Editor for non-Docker deployments. Changes: - Add `build:copy-system-prompts` script that recursively copies `src/agents/prompts/templates/` to `dist/agents/prompts/templates/` - Use `cp -r` for robustness (matches Docker COPY behavior) - Also fixes 11 lint warnings (noExplicitAny) in test files by: - Adding proper `mockAgentDefinition()` helper in modelResolution.test.ts - Using `Object.hasOwn()` instead of `as any` for property checks Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…592) The dashboard API was not calling initPrompts() at startup, causing the System Prompt tab in the Agent Definition Editor to show blank content. The prompts tRPC router calls getRawTemplate() which requires initPrompts() to be called first. Changes: - Add initPrompts() call in async startDashboard() function - Add proper error handling with Sentry capture and flush before exit - Match the startup pattern used in src/router/index.ts Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…d modules (#590) Co-authored-by: Cascade Bot <bot@cascade.dev>
#593) Replace the ad-hoc capability system with a unified capability-centric architecture where integrations provide capabilities and capabilities provide tools. Key changes: **New capability system (`src/agents/capabilities/`):** - Add capability registry mapping capabilities to gadgets and SDK tools - Add resolver functions for deriving integrations from capabilities - Add `resolveEffectiveCapabilities()` for runtime optional capability filtering - Add `createIntegrationChecker()` factory for project integration lookups - Add `generateUnavailableCapabilitiesNote()` for system prompt injection **Schema changes (`src/agents/definitions/schema.ts`):** - Replace boolean capability flags with typed capability arrays - `capabilities: { required: Capability[], optional: Capability[] }` - Remove separate `integrations` and `tools` sections (now derived) - Remove `gadgetBuilder` strategy (replaced by capability-based building) **Agent definition updates (all YAML files):** - Migrate all 10 agent definitions to new capability format - debug.yaml: Remove fs:write (read-only analysis agent) - respond-to-ci.yaml: Add pm:checklist to optional capabilities **Runtime improvements:** - Wire `IntegrationChecker` through profiles.ts and llmist backend - Optional capabilities filtered by actual project integration availability - Fix: Throw on missing gadget constructors (was silently skipped) - Fix: Only fall back to full access for "not found" errors in legacy shim - Fix: Pass correct agentType to preExecute hooks - Add validation warning for missing tools in filterToolManifests **Test coverage:** - Add comprehensive resolver.test.ts for capability resolution functions - Update all affected tests for new capability format - Add mock for createIntegrationChecker in llmist tests This refactoring: - Eliminates redundancy between schema and runtime capability logic - Makes integration requirements derivable from capability declarations - Provides architectural safety (tools don't exist if cap not enabled) - Enables graceful degradation for optional integrations Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
#594) * refactor(agents): implement integration-driven capability architecture Replace the ad-hoc capability system with a unified capability-centric architecture where integrations provide capabilities and capabilities provide tools. Key changes: **New capability system (`src/agents/capabilities/`):** - Add capability registry mapping capabilities to gadgets and SDK tools - Add resolver functions for deriving integrations from capabilities - Add `resolveEffectiveCapabilities()` for runtime optional capability filtering - Add `createIntegrationChecker()` factory for project integration lookups - Add `generateUnavailableCapabilitiesNote()` for system prompt injection **Schema changes (`src/agents/definitions/schema.ts`):** - Replace boolean capability flags with typed capability arrays - `capabilities: { required: Capability[], optional: Capability[] }` - Remove separate `integrations` and `tools` sections (now derived) - Remove `gadgetBuilder` strategy (replaced by capability-based building) **Agent definition updates (all YAML files):** - Migrate all 10 agent definitions to new capability format - debug.yaml: Remove fs:write (read-only analysis agent) - respond-to-ci.yaml: Add pm:checklist to optional capabilities **Runtime improvements:** - Wire `IntegrationChecker` through profiles.ts and llmist backend - Optional capabilities filtered by actual project integration availability - Fix: Throw on missing gadget constructors (was silently skipped) - Fix: Only fall back to full access for "not found" errors in legacy shim - Fix: Pass correct agentType to preExecute hooks - Add validation warning for missing tools in filterToolManifests **Test coverage:** - Add comprehensive resolver.test.ts for capability resolution functions - Update all affected tests for new capability format - Add mock for createIntegrationChecker in llmist tests This refactoring: - Eliminates redundancy between schema and runtime capability logic - Makes integration requirements derivable from capability declarations - Provides architectural safety (tools don't exist if cap not enabled) - Enables graceful degradation for optional integrations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(claude-code): add context offloading for large context injections When context injections exceed the inline threshold (8k tokens), offload them to files under .cascade/context/ and instruct Claude to read them on-demand using its Read tool. This prevents prompt size issues with large PR diffs or file contents. Key changes: - Add contextFiles.ts module with offloadLargeContext, cleanupContextFiles - Add CONTEXT_OFFLOAD_CONFIG with inlineThreshold, contextDir, enabled - Update buildTaskPrompt to be async and handle context offloading - Auto-cleanup context files after agent execution via try/finally - Slugify filenames with index suffix to prevent collisions - Use POSIX paths for cross-platform consistency in instructions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 - Critical Backend Fixes: - Add missing AgentInput fields (triggerCommentBody, triggerCommentPath) for PR comment triggers - Create unified buildTaskPromptContext() in prompts/index.ts with consistent null handling - Fix modelResolution.ts to use renderInlineTaskPrompt() instead of renderCustomPrompt() - Add schema validation requiring prompts.taskPrompt (PromptsSchema no longer optional) - Add early Eta syntax validation in profile builder to catch errors at build time Phase 2 - Dashboard Fixes: - Fix save logic to always send both prompts (prevents losing inactive section) - Fix reset button: rename to "Reset All Prompts" and add confirmation dialog - Show variable descriptions in ReferencePanel - Add loading/error states in PromptsPanel - Refactor PromptsPanel to reduce cognitive complexity (extract helper components) Phase 3 - Consistency Cleanup: - Standardize YAML taskPrompt format to pipe style (debug, planning, splitting, implementation) - Remove unnecessary dbPartials size check in getSystemPrompt() and renderInlineTaskPrompt() - Add placeholder text for system prompt textarea Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…YAML) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…-review fix(agents): address inline task prompts code review findings
…chitecture
Schema validation improvements:
- Add TriggerEventSchema with regex validation for {category}:{event-name} format
- Add KnownProviderSchema enum (trello, jira, github, imap, gmail, twilio)
- Add defaultValue type consistency refinement (must match parameter type)
- Add refinement preventing required: true with defaultValue
- Add IntegrationRequirementsSchema overlap refinement
Repository fixes:
- Fix bulkUpsertTriggerConfigs bug (was using first config's values for all conflicts)
- Add getTriggerConfigById function for ownership verification
- Use individual upserts in transaction for correct per-config values
Router refactoring:
- Replace direct DB access with repository functions in update/delete procedures
- Clean up imports (remove unused getDb, eq)
YAML definition fixes:
- review.yaml: consolidate duplicate scm:check-suite-success triggers into single
trigger with authorMode select parameter (own/external/all)
- debug.yaml: remove undeclared pm:attachment-added trigger (agent is manually triggered)
- implementation.yaml, planning.yaml, splitting.yaml: remove contradictory
required: true from parameters that have defaultValue
Tests:
- Add comprehensive tests for TriggerParameterSchema validation
- Add tests for SupportedTriggerSchema event format validation
- Add tests for KnownProviderSchema
- Add tests for IntegrationRequirementsSchema overlap
- Add tests for AgentDefinitionSchema with triggers
- Add full test suite for agentTriggerConfigs router (51 new tests)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `triggers: []` to EMPTY_DEFINITION in agent-definition-editor.tsx to satisfy the TypeScript type now that triggers is a required field in AgentDefinition. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…-architecture fix(triggers): address code review findings for integration-driven architecture
The previous fix (7d45347) only updated package.json but missed Dockerfile.worker. Task templates are now inline in YAML definitions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same fix as Dockerfile.worker - task templates are now inline in YAML. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… migration (#597) Introduces a definition-driven trigger configuration system that replaces the legacy per-integration trigger config approach with a unified model. Unified Trigger CLI Commands: - Add `cascade projects trigger-set` - replaces pm-trigger-set and review-trigger-set - Add `cascade projects trigger-list` - list configured triggers for a project - Add `cascade projects trigger-discover` - discover triggers from agent definitions - Remove deprecated `pm-trigger-set` and `review-trigger-set` commands Definition-Based Trigger System: - Add `triggers` array to agent YAML definitions - Add `SupportedTrigger` schema with event, label, parameters, providers - Add `TriggerParameter` schema (string, email, boolean, select types) - Use category-prefixed format: `{category}:{event-name}` Trigger Config Resolution: - Rewrite `config-resolver.ts` to merge definition defaults with DB overrides - Add `isTriggerEnabled()`, `getTriggerParameters()`, `resolveTriggerConfigs()` - Resolution order: DB config > definition default Dashboard Integration: - Add `getProjectTriggersView` tRPC endpoint for composite trigger data - Add `DefinitionTriggerToggles` component for triggers with parameters - Add `TriggerParameterInput` component for parameter editing - Simplify `trigger-agent-mapping.ts` to re-export from shared types Auto-Deploy Migration: - Add `tools/migrate-triggers.ts` for migrating legacy triggers - Add `tool:migrate-triggers` npm script - Add trigger migration step to deploy.yml and deploy-dev.yml workflows - Migration runs after drizzle schema migrations, is idempotent Tests & Documentation: - Add tests for shared trigger types (`triggerTypes.test.ts`) - Expand tests for trigger utility functions (`triggerAgentMapping.test.ts`) - Update CLAUDE.md with new CLI commands and trigger format docs Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The trigger migration script needs to be available in the builder image. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…egistry (#598) - Add missing GitHub triggers (scm:pr-merged, scm:pr-ready-to-merge) to TRIGGER_REGISTRY - Use proper literal types (ContextStepName[], KnownProvider[]) instead of string[] - Remove duplicate TRIGGER_CATEGORY_LABELS from frontend (import from shared types) - Remove duplicate type definitions from CLI triggers.ts (import from shared modules) - Standardize trigger descriptions to consistent past tense verb phrases - Add comprehensive unit tests for TRIGGER_REGISTRY - Export ContextStepName and KnownProvider types from triggerTypes.ts for consumers Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
) This refactoring moves context pipeline configuration from a global default in `strategies.contextPipeline` to trigger-specific definitions. This provides more explicit control over what context each trigger fetches. ## Changes ### Schema (`schema.ts`) - Remove `contextPipeline` from `StrategiesSchema` - Update comment to clarify context step names are only used by triggers - Update JSDoc for `contextPipeline` in `SupportedTriggerSchema` ### Profile Resolution (`profiles.ts`) - Simplify `resolveContextPipeline()` to only use trigger-defined pipelines - Return empty array when no trigger matches (no default fallback) - Add comprehensive JSDoc documenting edge cases ### Agent Definitions (YAML) - Move `contextPipeline` from `strategies` to each trigger definition - `strategies` now only contains `gadgetOptions` (or empty object) - Fix respond-to-review.yaml taskPrompt (was copy-pasted from respond-to-pr-comment) - Add missing `trailingMessage` to respond-to-pr-comment.yaml for consistency ### API Router - Remove `contextStepNames` from schema endpoint (no longer needed by frontend) ### Dashboard UI - Remove context pipeline editor from strategies section - Strategies section now only shows gadgetOptions when present - Clean up unused schema data ### Tests - Update loader tests to use trigger-defined pipelines - Update schema tests to remove strategies.contextPipeline assertions - Add edge case tests for resolveContextPipeline: - Returns empty array when triggerType is undefined - Returns empty array when triggerType matches no trigger - Returns empty array for agents with no triggers (debug) - Returns empty array when triggerType is empty string ## Benefits 1. **Explicit context per trigger**: Each trigger clearly defines what context it needs, making the configuration more transparent 2. **No hidden defaults**: Removed the fallback behavior that could mask misconfiguration 3. **Simpler mental model**: One place to look for context configuration 4. **Better for review agents**: SCM-triggered agents don't accidentally fetch PM context they don't need Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
… in agent definition editor (#602) * feat(dashboard): extract Capabilities and Triggers into separate tabs in agent definition editor Moves CapabilitiesSection and TriggersSection out of the monolithic Definition tab into their own dedicated tabs. Updates handleTabChange to sync JSON ↔ all structured tabs (definition, capabilities, triggers). Tab order: Definition | Capabilities | Triggers | Prompts (edit only) | Raw JSON Closes: https://trello.com/c/69a56e72a79db92b36d7a9e3 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(dashboard): extract Capabilities and Triggers into separate tabs in agent definition editor --------- Co-authored-by: Cascade Bot <bot@cascade.dev> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…onfig (#603) Co-authored-by: Cascade Bot <bot@cascade.dev>
…#604) Co-authored-by: Cascade Bot <bot@cascade.dev>
…coped infrastructure (#606) Co-authored-by: Cascade Bot <bot@cascade.dev>
* feat(triggers): unify PM trigger naming to pm:status-changed Consolidates the provider-specific `pm:card-moved` (Trello) and `pm:issue-transitioned` (Jira) events into a single `pm:status-changed` trigger that works across all PM integrations at the category level. Key changes: - TRIGGER_REGISTRY: replace two PM entries with unified pm:status-changed - Agent YAMLs: merge two triggers into single pm:status-changed per agent - New handlers: TrelloStatusChangedTrigger, JiraStatusChangedTrigger - New Trello types: moved TrelloWebhookPayload to src/triggers/trello/types.ts - Config schema: add statusChanged key (replaces cardMovedTo*/issueTransitioned) - Backward compat: legacy config keys still parsed and resolved - Migration tool: maps old event names to pm:status-changed - All tests updated/rewritten for new naming Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update CLAUDE.md trigger references to pm:status-changed Replace stale pm:card-moved and pm:issue-transitioned references with the unified pm:status-changed event name throughout the Agent Trigger Configuration section. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(triggers): remove dead card-moved and issue-transitioned files Delete old trigger handlers and their orphaned tests that were replaced by the unified status-changed triggers but left on disk. Removed files: - src/triggers/trello/card-moved.ts - src/triggers/jira/issue-transitioned.ts - tests/unit/triggers/card-moved.test.ts - tests/unit/triggers/jira-issue-transitioned.test.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(triggers): add per-agent granularity and legacy fallback for Trello status-changed Address review feedback on PR #605: Issue 1: Trello triggers now support per-agent granularity - Changed TrelloTriggerConfigSchema.statusChanged from z.boolean() to StatusChangedSchema - This allows statusChanged to accept both boolean and per-agent objects like Jira - Config examples: statusChanged: false (all agents) or { splitting: true, planning: false, implementation: true } Issue 2: Legacy Trello config keys now work via fallback - Added resolveTrelloStatusChangedEnabled() function with fallback pattern like Jira's resolveStatusChangedEnabled() - Falls back to cardMovedToSplitting/cardMovedToPlanning/cardMovedToTodo when statusChanged not set - Trigger handlers now use resolveTrelloStatusChangedEnabled() instead of resolveTrelloTriggerEnabled() - Legacy keys are no longer silently dead - they work when statusChanged is absent Added comprehensive tests for new per-agent and fallback behavior. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Cascade Bot <bot@cascade.dev> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…to ack infrastructure (#607) * refactor(agents): remove preExecute hook - move postInitialPRComment to ack infrastructure * fix(ci): remove remaining preExecute references from test and frontend editor The loader test still had an assertion checking def.backend.preExecute, and the agent definition editor still rendered a Pre-Execute Hook select dropdown, both referencing the removed preExecute schema property. 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>
…ion unconditional (#608) Co-authored-by: Cascade Bot <bot@cascade.dev>
Previously, when `cascade-tools pm post-comment` attempted to update an existing progress comment and failed, the error was silently swallowed with no logging, making debugging production failures impossible. This adds WARN level logging to the catch block in postComment.ts, matching the pattern used in PMProgressPoster (pmPoster.ts). The log includes workItemId, commentId, and error message for debugging. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
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 dev branch to main, including:
cascade-tools pm post-commentfails to update an existing progress comment, matching the pattern used inPMProgressPosterTest plan
🤖 Generated with Claude Code