* improvement(landing): optimize core web vitals and accessibility
Code-split AuthModal and DemoRequestModal via next/dynamic across 7 landing
components to move auth-client bundle (~150-250KB) out of the initial JS payload.
Replace useSession import in navbar with direct SessionContext read to avoid
pulling the entire better-auth client into the landing page bundle. Add immutable
cache header for content-hashed _next/static assets. Defer PostHog session
recording until user identification to avoid loading the recorder (~80KB) on
anonymous visits. Fix accessibility issues flagged by Lighthouse: add missing
aria-label on preview submit button, add inert to aria-hidden ReactFlow wrapper,
set decorative alt on logos inside labeled links, disambiguate duplicate footer
API links.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(posthog): guard startSessionRecording against repeated calls on refetch
The effect fires on every session reload (e.g., subscription upgrade).
Calling startSessionRecording() while already recording fragments the
session in the analytics dashboard. Add sessionRecordingStarted() guard
so recording only starts once per page lifecycle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(config): remove redundant _next/static cache header
Next.js already sets Cache-Control: public, max-age=31536000, immutable
on _next/static assets natively and this cannot be overridden. The custom
rule was redundant on Vercel and conflicted with the extension-based rule
on self-hosted deployments due to last-match-wins ordering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(brightdata): use params for echo-back fields in transformResponse
transformResponse receives params as its second argument. Use it to
return the original url, query, snapshotId, and searchEngine values
instead of hardcoding null or extracting from response data that may
not contain them.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(brightdata): handle async Discover API with polling
The Bright Data Discover API is asynchronous — POST /discover returns
a task_id, and results must be polled via GET /discover?task_id=...
The previous implementation incorrectly treated it as synchronous,
always returning empty results.
Uses postProcess (matching Firecrawl crawl pattern) to poll every 3s
with a 120s timeout until status is "done".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(brightdata): alphabetize block registry entry
Move box before brandfetch/brightdata to maintain alphabetical ordering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
* fix(brightdata): return error objects instead of throwing in postProcess
The executor wraps postProcess in try-catch and falls back to the
intermediate transformResponse result on error, which has success: true
with empty results. Throwing errors would silently return empty results.
Match Firecrawl's pattern: return { ...result, success: false, error }
instead of throwing. Also add taskId to BrightDataDiscoverResponse type
to eliminate unsafe casts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(brightdata): use platform execution timeout for Discover polling
Replace hardcoded 120s timeout with DEFAULT_EXECUTION_TIMEOUT_MS to
match Firecrawl and other async polling tools. Respects platform-
configured limits (300s free, 3000s paid).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Derive sidebar open state from selection validity instead of using a
separate useEffect. Also removes unnecessary useMemo/useCallback in
non-memo'd components, replaces useEffect with render-time reset in
dashboard, fixes CSS tokens, and adds hierarchical query key factory.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(brightdata): add Bright Data integration with 8 tools
Add complete Bright Data integration supporting Web Unlocker, SERP API,
Discover API, and Web Scraper dataset operations. Includes scrape URL,
SERP search, discover, sync scrape, scrape dataset, snapshot status,
download snapshot, and cancel snapshot tools.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(brightdata): address PR review feedback
- Fix truncated "Download Snapshot" description in integrations.json and docs
- Map engine-specific query params (num/count/numdoc, hl/setLang/lang/kl,
gl/cc/lr) per search engine instead of using Google-specific params for all
- Attempt to parse snapshot_id from cancel/download response bodies instead
of hardcoding null
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
* fix(agiloft): change bgColor to white; fix docs truncation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(brightdata): avoid inner quotes in description to fix docs generation
The docs generator regex truncates at inner quotes. Reword the
download_snapshot description to avoid embedded double quotes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(brightdata): disable incompatible DuckDuckGo and Yandex URL params
DuckDuckGo kl expects region-language format (us-en) and Yandex lr
expects numeric region IDs (213), not plain two-letter codes. Disable
these URL-level params since Bright Data normalizes localization through
the body-level country param.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(seo): optimize sitemaps and robots.txt across sim and docs
- Add missing pages to sim sitemap: blog author pages, academy catalog and course pages
- Fix 6x duplicate URL bug in docs sitemap by deduplicating with source.getLanguages()
- Convert docs sitemap from route handler to Next.js metadata convention with native hreflang
- Add x-default hreflang alternate for docs multi-language pages
- Remove changeFrequency and priority fields (Google ignores both)
- Fix inaccurate lastModified timestamps — derive from real content dates, omit when unknown
- Consolidate 20+ redundant per-bot robots rules into single wildcard entry
- Add /form/ and /credential-account/ to sim robots disallow list
- Reference image sitemap in sim robots.txt
- Remove deprecated host directive from sim robots
- Move disallow rules before allow in docs robots for crawler compatibility
- Extract hardcoded docs baseUrl to env variable with production fallback
* fix(seo): remove homepage new Date(), guard latestModelDate empty array
* improvement(seo): consolidate DOCS_BASE_URL, optimize core web vitals
Extract hardcoded https://docs.sim.ai into shared DOCS_BASE_URL constant
in lib/urls.ts and replace all 20+ instances across layouts, metadata,
structured data, LLM manifest, sitemap, and robots files. Remove
OneDollarStats analytics script and tighten CSP for improved core web vitals.
* fix: removed onedollarstats from bun lock
* fix(seo): guard per-provider Math.max, consolidate docs robots to single wildcard
* v0.6.29: login improvements, posthog telemetry (#4026)
* feat(posthog): Add tracking on mothership abort (#4023)
Co-authored-by: Theodore Li <theo@sim.ai>
* fix(login): fix captcha headers for manual login (#4025)
* fix(signup): fix turnstile key loading
* fix(login): fix captcha header passing
* Catch user already exists, remove login form captcha
* fix(landing): return 404 for invalid dynamic route slugs
Add `dynamicParams = false` to all landing page dynamic routes so
Next.js returns a proper 404 instead of a client-side exception for
slugs not in generateStaticParams.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(home): remove duplicate handleStopGeneration declaration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Theodore Li <theodoreqili@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(microsoft-excel): export GRAPH_ID_PATTERN and reuse across routes
Export the shared regex pattern from utils.ts and import it in files/route.ts
and drives/route.ts instead of duplicating the inline pattern. Also reorders
the TSDoc comment to sit above getItemBasePath where it belongs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(microsoft-excel): add SharePoint drive support for Excel integration
* fix(microsoft-excel): address PR review comments
- Validate siteId/driveId format in drives route to prevent path traversal
- Use direct single-drive endpoint for fetchById instead of filtering full list
- Fix dependsOn on sheet/spreadsheet selectors so driveId flows into context
- Fix NextRequest type in drives route for build compatibility
* fix(microsoft-excel): validate driveId in files route
Add regex validation for driveId query param in the Microsoft OAuth
files route to prevent path traversal, matching the drives route.
* fix(microsoft-excel): unblock OneDrive users and validate driveId in sheets route
- Add credential to any[] arrays so OneDrive users (no drive selected)
still pass the dependsOn gate while driveSelector remains in the
dependency list for context flow to SharePoint users
- Add /^[\w-]+$/ validation for driveId in sheets API route
* fix(microsoft-excel): validate driveId in getItemBasePath utility
Add regex validation for driveId at the shared utility level to prevent
path traversal through the tool execution path, which bypasses the
API route validators.
* fix(microsoft-excel): use centralized input validation
Replace inline regex validation with platform validators from
@/lib/core/security/input-validation:
- validateSharePointSiteId for siteId in drives route
- validateAlphanumericId for driveId in drives, sheets, files routes
and getItemBasePath utility
* lint
* improvement(microsoft-excel): add File Source dropdown to control SharePoint visibility
Replace always-visible optional SharePoint fields with a File Source
dropdown (OneDrive/SharePoint) that conditionally shows site and drive
selectors. OneDrive users see zero extra fields (default). SharePoint
users switch the dropdown and get the full cascade.
* fix(microsoft-excel): fix canonical param test failures
Make fileSource dropdown mode:'both' so it appears in basic and advanced
modes. Add condition to manualDriveId to match driveSelector's condition,
satisfying the canonical pair consistency test.
* fix(microsoft-excel): address PR review feedback for SharePoint drive support
- Clear stale driveId/siteId/spreadsheetId when fileSource changes by adding
fileSource to dependsOn arrays for siteSelector, driveSelector, and
spreadsheetId selectors
- Reorder manualDriveId before manualSpreadsheetId in advanced mode for
logical top-down flow
- Validate spreadsheetId with validateMicrosoftGraphId in getItemBasePath()
and sheets route to close injection vector (uses permissive validator that
accepts ! chars in OneDrive item IDs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(microsoft-excel): use validateMicrosoftGraphId for driveId validation
SharePoint drive IDs use the format b!<base64-string> which contains !
characters rejected by validateAlphanumericId. Switch all driveId
validation to validateMicrosoftGraphId which blocks path traversal and
control characters while accepting valid Microsoft Graph identifiers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(microsoft-excel): use validatePathSegment with strict pattern for driveId/spreadsheetId
Replace validateMicrosoftGraphId with validatePathSegment using a custom
pattern ^[a-zA-Z0-9!_-]+$ for all URL-interpolated IDs. validatePathSegment
blocks /, \, path traversal, and null bytes before checking the pattern,
preventing URL-modifying characters like ?, #, & from altering the Graph
API endpoint. The pattern allows ! for SharePoint b!<base64> drive IDs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
* fix(microsoft-excel): reorder driveId before spreadsheetId in v1 block
Move driveId subBlock before manualSpreadsheetId in the legacy v1 block
to match the logical top-down flow (Drive ID → Spreadsheet ID), consistent
with the v2 block ordering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(microsoft-excel): clear manualDriveId when fileSource changes
Add dependsOn: ['fileSource'] to manualDriveId so its value is cleared
when switching from SharePoint back to OneDrive. Without this, the stale
driveId would still be serialized and forwarded to getItemBasePath,
routing through the SharePoint drive path instead of me/drive.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(microsoft-excel): use getItemBasePath in sheets route to remove duplication
Replace inline URL construction and validation logic with the shared
getItemBasePath utility, eliminating duplicated GRAPH_ID_PATTERN regex
and conditional URL building.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(blocks): correct required field validation for Jira and Confluence blocks
Jira: summary is only required for create (not update), projectId is not required for update (API uses issueKey). Confluence: title and content are required for page creation, title is required for blog post creation — all enforced by backend validation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(blocks): remove projectId dependsOn gate for update fields, require content for blog post creation
Jira: Remove dependsOn projectId from shared write/update fields — projectId is not required for update so the gate would disable all update fields when no project is selected. Write-only fields (issueType, parentIssue, reporter) retain the gate since projectId is required for create.
Confluence V2: Add create_blogpost to content required condition — backend Zod schema enforces content for blog post creation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The PlayOutline icon had a non-standard viewBox and mismatched path,
causing it to render at an inconsistent size and shape compared to the
filled Play icon and other action bar icons.
* fix(seo): correct canonical URLs, compress oversized images, add cache headers
- Replace all hardcoded https://sim.ai with https://www.sim.ai via SITE_URL constant
- Migrate models, integrations, and homepage metadata from getBaseUrl() to SITE_URL
- Compress 6 blog/landing images from 2.6MB to 300KB total
- Convert mothership cover from PNG to JPEG (1.1MB → 99KB)
- Add Cache-Control headers for static assets (1d max-age, 7d stale-while-revalidate)
- Add SEO regression test scanning all public pages for canonical URL violations
* fix(seo): replace hardcoded URLs with SITE_URL, broaden test detection
- Replace hardcoded https://www.sim.ai with SITE_URL in academy, changelog.xml, and whitelabeling
- Broaden getBaseUrl() detection in SEO test to match any variable name assignment
- Add ee/whitelabeling/metadata.ts to SEO test scan scope
* improvement(ui): delegate streaming animation to Streamdown component
Remove custom useStreamingText hook and useThrottledValue indirection
in favor of Streamdown's built-in streaming props. This eliminates the
manual character-by-character reveal logic (setInterval, easing, chase
factor) and lets the library handle animation natively, reducing
complexity and improving consistency across Mothership and chat.
* improvement(ui): inline passthrough wrapper, add hydration guard
- Inline EnhancedMarkdownRenderer which became a trivial passthrough
after removing useThrottledValue
- Add hydration guard to MarkdownRenderer to prevent replaying the
entrance animation when mounting mid-stream with existing content
* improvement: removed chat animation
* improvement(ui): remove hardcoded fade-in animations from special tags
Remove animate-stream-fade-in from OptionsDisplay, CredentialDisplay,
MothershipErrorDisplay, and UsageUpgradeDisplay. These components
re-render after streaming ends, causing a visible flash as the
opacity animation replays. PendingTagIndicator retains its animation
since it only renders during active streaming.
* fix(ui): use streaming mode for Streamdown during active streams
mode='static' disables Remend (auto-closing incomplete markdown),
incremental block splitting, and React Transitions. Switch to
streaming mode while isStreaming is true so partial markdown renders
correctly, without re-adding animation props.
* fix(security): resolve ReDoS vulnerability in function execute tag pattern
Simplified regex to eliminate overlapping quantifiers that caused exponential
backtracking on malformed input without closing delimiter.
* feat(jira): support raw ADF document objects in description and environment fields
Add toAdf() helper that passes through ADF objects as-is or wraps plain
text in a single-paragraph ADF doc. Update write and update routes to
use it, replacing inline ADF wrapping. Update Zod schema to accept
string or object for description. Fully backward compatible — plain
text still works, but callers can now pass rich ADF with expand nodes,
tables, code blocks, etc.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(jira): handle partial ADF nodes and non-ADF objects in toAdf()
Wrap partial ADF nodes (type + content but not doc) in a doc envelope.
Fall back to JSON.stringify for non-ADF objects instead of String()
which produces [object Object].
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint
* fix(jira): handle JSON-stringified ADF in toAdf() for variable resolution
The executor's formatValueForBlock() JSON.stringify's object values when
resolving <Block.output> references. This means an ADF object from an
upstream Agent block arrives at the route as a JSON string. toAdf() now
detects JSON strings containing valid ADF documents or nodes and parses
them back, ensuring rich formatting is preserved through the pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* lint changes
* fix(jira): update environment Zod schema to accept ADF objects
Match the description field schema change — environment also passes
through toAdf() so its Zod schema must accept objects too.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* updated lobkc
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(google-drive): add auto export format and Azure storage debug logging
* chore: remove Azure storage debug logging
* fix(google-drive): use status-based fallback instead of string matching for export errors
* fix(google-drive): validate export formats against Drive API docs, remove fallback
* fix(google-drive): use value function for dropdown default
* fix(google-drive): add text/markdown to valid export formats for Google Docs
* fix(google-drive): correct ODS MIME type for Sheets export format
* fix(ci): replace dynamic secret access with explicit secret references
Resolves CodeQL "Excessive Secrets Exposure" warning by replacing
secrets[matrix.ecr_repo_secret] with conditional expressions that
reference only the specific secrets needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ci): add explicit ECR_REALTIME guard and use env block for secret injection
- Prevent silent fallthrough to ECR_REALTIME for unrecognized secret keys
- Move build-amd64 secret resolution to env: block matching build-dev pattern
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* improvement(ui): restore smooth streaming animation, fix follow-up auto-scroll, move CopyCodeButton to emcn
* fix(ui): restore delayed animation, handle tilde fences, fix follow-up scroll root cause
* fix(ui): extract useStreamingReveal to followup, keep cleanup changes
* fix(ui): restore hydratedStreamingRef for reconnect path order-of-ops
* fix(ui): restore full hydratedStreamingRef effect for reconnect path
* fix(ui): use hover-hover prefix on CopyCodeButton callers to correctly override ghost variant
* fix(logs): remove destructive color from cancel execution menu item
* feat(logs): optimistic cancelling status on cancel execution
* feat(logs): allow cancellation of pending (paused) executions
* fix(hitl): cancel paused executions directly in DB
Paused HITL executions are idle in the DB — they don't poll Redis or
run in-process, so the existing cancel signals had no effect. The DB
status stayed 'pending', causing the optimistic 'cancelling' update to
revert on refetch.
- Add PauseResumeManager.cancelPausedExecution: atomically sets
paused_executions.status and workflow_execution_logs.status to
'cancelled' inside a FOR UPDATE transaction
- Guard enqueueOrStartResume against resuming a cancelled execution
- Include pausedCancelled in the cancel route success check
* upgrade turbo
* test(hitl): update cancel route tests for paused execution cancellation
- Mock PauseResumeManager.cancelPausedExecution to prevent DB calls
- Add pausedCancelled to all expected response objects
- Add test for HITL paused execution cancellation path
- Add missing auth/authz tests
- Switch to vi.hoisted pattern for all mocks
* fix(hitl): set endedAt when cancelling paused execution
Without endedAt, the logs API running filter (isNull(endedAt)) would
keep cancelled paused executions in the running view indefinitely.
* fix(hitl): emit execution:cancelled event to canvas when cancelling paused execution
Paused HITL executions have no active SSE stream, so the canvas never
received the cancellation event. Now writes execution:cancelled to the
event buffer and updates the stream meta so the canvas reconnect path
picks it up and shows 'Execution Cancelled'.
* fix(hitl): isolate cancelPausedExecution failure from successful cancellation
Wrap cancelPausedExecution in try/catch so a DB error does not mask
a prior successful Redis or in-process cancellation. Also move the
resource-collapse side effect in home.tsx to a useEffect to avoid the
stale closure on the resources array.
* fix(hitl): add .catch() to fire-and-forget event buffer calls in cancel route
* fix(security): resolve ReDoS vulnerability in function execute tag pattern
Simplified regex to eliminate overlapping quantifiers that caused exponential
backtracking on malformed input without closing delimiter.
* fix(security): exclude trailing-dot refs and hoist tag pattern to module level
* fix(security): align tag pattern with codebase standard [^<>]+ pattern
Matches createReferencePattern() from reference-validation.ts used by the
core executor. Invalid refs handled gracefully by resolveBlockReference.
* refactor(security): use createReferencePattern() instead of inline regex
getTrigger() namespaces condition-gated subBlock IDs (e.g. webhookUrlDisplay
→ webhookUrlDisplay_github_release_published). The block card's useMemo was
checking for an exact match on 'webhookUrlDisplay', which never matched.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(jsm): add all Forms API endpoints for two-step form workflow
* removed tyoes
* fix(jsm): handle 204 No Content on action endpoints and reject array answers
* fix(jsm): validate formIds is an array in copy_forms route and block
* fix(jsm): add formTemplateId validation and conditional required on formAnswers
* feat(aws): add IAM and STS integrations
* fix(sts): address PR review comments
- Fix CrowdStrike tags to include "security" (unintended removal)
- Standardize STS tool versions to '1.0.0' (matching IAM convention)
- Add range validation to durationSeconds in Zod schemas
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* icon
* lint
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Auto-focus input boxes for modals and copilot
* Fix focus in emcn modal
* Fix integrations manager focus
* Change modal tabs to auto focus on first text input
* Auto-focus mothership task chats
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* feat(workspaces): add workspace logo upload
* feat(workspaces): add workspace logo upload
* fix(workspaces): validate logoUrl accepts only paths or HTTPS URLs
* fix(workspaces): add admin authorization, audit log, and posthog event for workspace logo uploads
* lint
* fix: add WebP support and use refs pattern in useProfilePictureUpload
- Add image/webp to ACCEPTED_IMAGE_TYPES in useProfilePictureUpload
- Add image/webp to file input accept attributes in whitelabeling settings
- Refactor useProfilePictureUpload to use refs for onUpload, onError, and
currentImage callbacks, matching the established codebase pattern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore cloudwatch/cloudformation files from staging
These files were accidentally regressed during rebase conflict resolution,
reverting changes from #4027. Restoring to staging versions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add workspace_logo_uploaded to PostHogEventMap
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: separate workspaceId ref sync to prevent overwrite on re-render
Split the ref sync useEffect so workspaceIdRef only updates when the
workspaceId prop changes, not when onUpload/onError callbacks get new
references. Prevents setTargetWorkspaceId from being overwritten by
a re-render before the file upload completes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use Pick type for workspace dropdown in knowledge header
The shared Workspace type requires ownerId and other fields that aren't
available from the workspaces API response mapping. Use a Pick type to
accurately represent the subset of fields actually constructed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: replace raw fetch with useWorkspacesQuery in knowledge header
Remove useState + useEffect + fetch anti-pattern for loading workspaces.
Use useWorkspacesQuery from React Query with inline filter for write/admin
permissions. Eliminates ~30 lines of manual state management, any casts,
and the Pick type workaround.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(atlassian): unify error message extraction across all Jira, JSM, and Confluence routes
Add parseAtlassianErrorMessage() to jira/utils.ts as single source of truth for
parsing all 5 Atlassian error formats. Update 51 proxy routes (18 JSM, 5 Jira,
28 Confluence) to use it instead of hardcoded generic errors. Remove dead
errorExtractor field from 95 Atlassian tool files — the compat loop in
extractErrorMessage() already handles all formats without it. Consolidate
duplicate parseJsmErrorMessage into a re-export from the shared utility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review comments from Bugbot
- Remove debug logger.info for formAnswers in JSM request route
- Restore user-friendly spaceId error message in Confluence create-page route
- Restore details field in Jira write and update route error responses
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: remove re-exports from jsm/utils and import directly from source
Remove re-exports of getJiraCloudId, parseAtlassianErrorMessage, and
parseJsmErrorMessage from jsm/utils.ts. Update all 21 JSM routes to
import directly from @/tools/jira/utils per CLAUDE.md import rules.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* regen docs
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(agiloft): add Agiloft CLM integration with token-based auth
Add 12 tools (CRUD, search, select, saved search, attachments, lock),
block, icon, docs, and internal API route for file attachments.
Uses EWLogin/EWLogout for short-lived Bearer tokens — credentials
are never embedded in API request URLs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(agiloft): address PR review feedback
- Add HTTPS enforcement guard to agiloftLogin to prevent plaintext credential transit
- Add null guard on data.output in attach_file transformResponse
- Change empty AgiloftSavedSearchParams interface to type alias
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(agiloft): add SSRF protection via DNS validation on instanceUrl
Validates user-supplied instanceUrl against private/reserved IP ranges
using validateUrlWithDNS before making any outbound requests. Uses dynamic
import to avoid bundling Node.js dns module in client-side code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(agiloft): fix SSRF protection to avoid client bundle breakage
Replace dynamic import of input-validation.server (which Turbopack traces
into the client bundle) with client-safe validateExternalUrl in utils.ts.
Add full DNS-level SSRF validation via validateUrlWithDNS in the attach
API route (server-only file). This matches the Okta pattern for
directExecution tools and the textract pattern for API routes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(agiloft): use DELETE method for EWRemoveAttachment endpoint
The remove_attachment tool was incorrectly using GET instead of DELETE
for the Agiloft EWRemoveAttachment endpoint, which would cause removals
to fail at runtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(agiloft): correct HTTP methods and parameter names per Agiloft API docs
- EWRemoveAttachment uses GET, not DELETE (revert incorrect change)
- EWRetrieve uses `filePosition` parameter, not `position`
- EWAttach uses PUT, not POST
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>