* feat(clickup): add ClickUp integration with OAuth + API-token auth, 23 tools, block, and attachment upload
- 23 tools covering tasks (create/get/update/delete/list/search), comments
(create/get/update/delete), attachment upload, tags, members, custom
fields, and the workspace/space/folder/list hierarchy
- OAuth provider wiring (authorization-code flow, non-expiring tokens) plus
clickup-service-account token-paste credential (personal pk_ API tokens),
with a shared clickupAuthorizationHeader helper (pk_ tokens sent bare,
OAuth tokens as Bearer)
- File upload follows the internal-route pattern: contract-validated
/api/tools/clickup/upload-attachment builds the multipart form and
returns UserFiles
- ClickUp block with per-operation subBlocks, canonical file param,
BlockMeta templates/skills, and gradient brand icon
- Generated integration docs page + hand-written service-account guide
* fix(clickup): apply validation-audit fixes across tools, block, and upload route
- Map documented task fields that were dropped: markdown_description,
subtasks, watchers, custom_fields, time_spent, folder, space — making
the include_subtasks / include_markdown_description options observable
- Expand verified filters: assignees/tags/due-date ranges on get_tasks and
search_tasks, include_closed on search_tasks; add due_date_time /
start_date_time flags and update-task assignee add/remove
- Guard update_comment against an empty body and require comment text in
the block; prefer markdown_content over content on create_list and make
markdown reachable for lists in the UI
- Drop the unverified 'required' field from custom-field outputs; read
both err and error keys from ClickUp error bodies; correct notify_all
wording
- Upload route: 100MB size cap, shared attachment mapper with full
documented response fields (version, thumbnails), base-URL constant
* fix(docs): restore clickup-service-account guide and shield it from doc generation
The generator prunes integration pages it does not derive from blocks;
add the hand-written ClickUp API-token guide to
HANDWRITTEN_INTEGRATION_DOCS so regeneration cannot delete it.
* fix(clickup): address review findings — dedupe catalog entries, config-time list parent validation, upload memory cap, unique icon gradient ids
- Remove duplicated clickup entries in docs meta.json and integrations.json
introduced by a double docs regeneration
- Add a Location dropdown for Get Lists / Create List so the folder ID or
space ID is conditionally required at configuration time instead of
failing at run time
- Pass the 100MB cap into downloadServableFileFromStorage so oversized
files abort during download instead of after full buffering
- Use useId()-derived SVG gradient ids for ClickUpIcon in both icon files
* chore(clickup): format integrations.json entry per biome
* improvement(clickup): final validation-pass refinements across tools and block
- create_task: add doc-backed sprint points param (parity with update)
- get_tasks/search_tasks: expose include_markdown_description
- update_task legacy numeric priority in list responses mapped instead of
dropped; create_comment omits absent response fields instead of
emitting sentinel ''/0 values
- order_by only sent when explicitly chosen (Default sentinel); comment
text no longer UI-required for update_comment (resolve-only and
assignee-only updates are valid per the tool contract, which still
rejects an empty body)
- add_tag_to_task sends no request body per docs; upload tool tolerates
non-JSON error responses
* fix(clickup): tolerate nested user wrapper in member mapping
The task/list member endpoints document a flat member object; accept the
workspace-members-style nested { user: {...} } wrapper as well so both
shapes map correctly.
* fix(clickup): map size-limit errors from download/compile to a 400 upload-size response
downloadServableFileFromStorage enforces maxBytes on both the raw download
and the resolved (compiled) artifact via PayloadSizeLimitError; catch it in
the route so oversized content returns the intended 400 instead of
bubbling to the generic 500 handler.
* feat(clickup): add custom field values, checklists, and time tracking (15 tools, 38 total)
- Set/remove custom field values on tasks (PUT/DELETE /task/{id}/field/{field_id});
block value input parses JSON for structured field types, plain values pass through
- Checklist CRUD: create/rename/reorder/delete checklists and create/update/
delete checklist items (assign, resolve, nest), mapped from the documented
{checklist} response shape
- Time tracking: list entries in a date range (assignee/location filters,
task-tag and location-name includes), create/update/delete entries, start/
stop timers, and read the currently running timer; entries mapped from the
documented data envelope with negative-duration running semantics
- Block gains 15 operations with conditionally-required fields, timestamp
wand configs, tri-state billable/resolved dropdowns, and a single-location
filter selector matching the API's one-location-filter rule
* fix(clickup): new-tools audit fixes — POST for set custom field value, tolerant time-entry envelopes, richer mappings
- Set Custom Field Value uses POST per the live reference OpenAPI (the
llms mirror shows PUT; the reference console spec is authoritative)
- delete_time_entry maps the documented array envelope; create_time_entry
tolerates both data-wrapped and flat echo bodies
- Time entries surface task_tags and task_location so the include switches
are observable; checklists carry date_created
- Custom field value input parses any JSON literal (numbers, booleans,
arrays, objects) and passes plain text through
- Update Time Entry supports duration edits; single-assignee time ops get
their own field so a comma-separated list can't silently NaN out
* fix(clickup): send explicit date-time flags whenever a date is set
The due/start date-time switches previously only transmitted true; a
timed date could never be flipped back to date-only. The flag is now sent
as an explicit boolean whenever the corresponding date is provided and
omitted otherwise.
* improvement(clickup): final per-tool audit polish — checklist item children, tolerant comment date
- Checklist items surface the documented children array of nested item IDs
- create_comment tolerates a string-typed date in the response
* fix(clickup): reject empty update_task bodies with a clear local error, matching sibling update tools
* chore(pii): remove GLiNER/GPU image + add spaCy-skip fast path to CPU server
* feat(pii): restrict block-output redaction to regex-only entities
* fix(pii): derive spaCy-NER set from registry + skip fast path when score_threshold set
* fix(pii): include ORGANIZATION in app-side NER set (align with server)
* feat(instagram): add Instagram Login OAuth, tools, and block
* feat(instagram): add Gmail-style media uploads for publish ops
Resolve UserFiles to Meta-fetchable presigned HTTPS URLs (600s TTL) via
internal publish routes, and fix OAuth scope storage plus connect-draft
wiring so Instagram Login publishing is testable end-to-end.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(instagram): simplify messaging tools to direct requests, clean up types
* fix(instagram): parallelize carousel child polling, enforce 2-10 items, extend poll window and insights periods, use canonical user_id in OAuth callback
* fix(instagram): resolve user id from user_id only, accept numeric user_id
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(instagram): use form/query params for publish and comment endpoints, request message timestamps explicitly
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(instagram): normalize Graph ID outputs to strings so downstream .trim() calls are safe
Co-authored-by: Cursor <cursoragent@cursor.com>
* style(instagram): use brand gradient tile for the block icon
Match the official Instagram look by filling the tile with the orange–pink–purple radial gradient so the white camera glyph sits on a full-bleed brand background.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(instagram): tighten publish defaults and cloud-storage upload UX
Default Reel share-to-feed to Yes, drop unused media fields params, share publish transform helpers, and warn when cloud storage is missing for Meta-fetchable uploads.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(instagram): fail closed when cloud storage status is unknown
Treat loading/error as blocked for requiresCloudStorage uploads, show the warning once the check finishes, and disable selecting local workspace files Meta cannot fetch.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(instagram): proactively refresh long-lived tokens before expiry
Meta only allows refreshing still-valid Instagram tokens, so refresh within 14 days of expiry (after the 24h age gate) instead of waiting until after accessTokenExpiresAt.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(oauth): restore TikTok clientIdParamName JSDoc after merge
The staging merge dropped the opening /** on ProviderAuthConfig.clientIdParamName, which broke TypeScript parse in CI.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(api): Zod-contract storage-status and ratchet validation baseline
Wire /api/files/storage-status through a shared route contract so the
strict API validation audit stays at zero non-Zod routes after the new
Instagram cloud-storage check.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(instagram): match Gmail advanced media placeholders
Drop public-URL paste hints from advanced fields and the cloud-storage banner so the UI mirrors Gmail attachments.
Co-authored-by: Cursor <cursoragent@cursor.com>
* code review + hide from toolbar
* address comments
* fix(instagram): drop hidden Instagram from OAuth catalog pin test
Instagram is hideFromToolbar so it is excluded from integrations.json;
the pinned slug map must not expect it until the block is visible again.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(instagram): validate client ID before creating connect draft
Avoid orphan pending credential drafts when INSTAGRAM_CLIENT_ID is missing,
matching the Shopify authorize ordering.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* improvement(landing): SEO copy and metadata rewrite across marketing pages
* improvement(landing): remove em dashes from marketing copy
* fix(landing): name Sim in the knowledge base H1
* fix(workspace): recover from stale sessions instead of blank loader after impersonation
* fix(workspace): gate stale-session recovery on auth state and surface failed sign-out
* fix(workspace): proceed with redirect when session query errors but cached identity exists
* feat(credentials): token-paste service accounts for 12 providers (HubSpot, Airtable, Notion, Asana, Attio, Linear, monday, Shopify, Webflow, Trello, Cal.com, Wealthbox)
* refactor(credentials): registry-dispatch service accounts + doc-verified validator hardening
- Migrate Google/Atlassian/Slack service-account branches to the same
registry pattern as token-paste providers (builder + resolver maps,
unified required-fields contract validation)
- Fix Shopify service-account store domain never reaching tool URL builders
- Linear: rate-limit 400s no longer mislabeled as invalid credentials;
validation header matches runtime header rule
- Trello: server API key rejection no longer blamed on customer token
- Fleet-wide: network errors and non-JSON provider bodies map to
provider_unavailable via shared fetchProvider/parseProviderJson
- HubSpot: drop regional-host displayName upgrade; Wealthbox: explicit 402;
monday: provider-side GraphQL errors mapped correctly; Attio: null-body guard
* polish(credentials): ship-gate fixes, setup-guide docs, and lint pass for token service accounts
- 12 setup-guide docs pages (docs.sim.ai/integrations/<provider>-service-account)
incl. the Trello authorize-link flow the integration depends on
- Attio: HTTP 400 on /v2/self maps to invalid_credentials (live-verified)
- monday: scan all GraphQL errors for provider-side codes; no empty audit ids
- Compile-time descriptor/validator lockstep (typed registry) and
prototype-safe provider-id guard (Object.hasOwn)
- Shared errors.test.ts pinning fetchProvider/parseProviderJson/
throwForProviderResponse guarantees for all validators
- Stale TSDoc updated after the registry migration; biome organizeImports pass
* docs(credentials): vendor-doc accuracy pass on service-account setup guides
34 corrections from a 12-agent audit against live official vendor docs:
current HubSpot Development-area nav, Notion connections rename, monday
Developer Center paths, Shopify legacy-vs-Dev-Dashboard token flows, and
hedged wording for claims vendors do not document (expiry, limits)
* improvement(credentials): vendor-accurate credential nouns on connect surfaces
'Add service account' only where the vendor actually has service accounts
(Google, Atlassian); token-paste providers now use their own vocabulary via a
connectNoun descriptor field — 'Add private app token' (HubSpot), 'Add API key'
(Attio/Linear/Cal.com), 'Add personal access token' (Airtable), etc. Docs page
titles updated to match; slugs and internal provider ids unchanged
* fix(credentials): classify auth-shaped Shopify GraphQL errors as invalid credentials
Shopify can reject invalid or revoked shpat_ tokens with HTTP 200 and a
GraphQL error body instead of a 401; those now map to invalid_credentials
instead of a provider-outage message
* fix(credentials): empirically-grounded HubSpot token verification
Live probing showed the documented access-token-info route returns a bare
404 for unrecognized tokens (ambiguous with a missing route), so 404/400
now falls back to the Account Information API, which answers with a JSON
401 for rejected tokens and 200/403 for live ones — verified against the
real endpoints
* fix(credentials): review-round-2 fixes for service-account edge cases
- Shopify tools prefer the credential-validated store domain over the
block's auto-detected shopDomain (a store-bound token must hit its own store)
- Unknown non-empty service-account providerIds are rejected instead of
silently persisting as google-service-account (empty stays the legacy
Google fallback)
- Shopify/modal domain normalization strips URL paths ('https://x.myshopify.com/admin')
- monday: warning-class GraphQL errors no longer reject a token whose me
data proves it authenticated
* chore(credentials): format shopify validator test
* fix(credentials): cold-review hardening pass
- Object.hasOwn guards on all provider-id registry lookups (crafted
'__proto__'/'constructor' providerIds now 400 instead of 500) + regression test
- fetchProvider gets a 10s AbortSignal.timeout so a hung provider can't pin
the create/reconnect request
- HubSpot: unexpected 403 on the token-info route defers to the account-info
fallback instead of blaming the token
- Linear selector routes use the SDK apiKey option for lin_api_ keys (bare
header parity with the tools sweep)
- Docs: UI steps aligned to the vendor-noun connect labels; HubSpot
scope-propagation claims softened; Trello in-product-link promise corrected
* fix(docs): remove Ask AI widget
* improvement(landing): add visible FAQ schema, fix SEO redirects and Organization schema
- Move existing plain-markdown FAQ sections in 8 library posts + emcn blog
into the faq frontmatter array so they emit FAQPage JSON-LD (previously
visible text with zero structured data)
- Add new, fact-checked FAQ content to the 8 posts with none: openai-vs-n8n-vs-sim,
v0-5, enterprise, copilot, executor, multiplayer, mothership, series-a
- Add sales ContactPoint to the site-wide Organization schema
- Add 301 redirects for legitimate crawler/dead-link 404s (/$, /&, /Sim,
/homepage, /logo, /en-US) surfaced by an external SEO audit; left out
bot-noise paths, already-fixed OG image 404s (#5636), and *.sim.ai
customer chat subdomains that need manual DB verification, not a
blanket redirect
* revert(docs): restore Ask AI widget
Ask AI removal is a separate change, out of scope for this PR — restoring
the component, chat panel, api/chat route, and its deps to their
pre-existing state.
* fix(content): correct stale/mislabeled competitor facts surfaced in FAQ audit
- n8n's license is "fair-code" (n8n's own coined term), not "fair-use" —
a different legal concept entirely; fixed 4 occurrences
- Activepieces' integration count is 750+ per their live catalog, not the
280+ figure carried over from an older snapshot; fixed 4 occurrences
across best-zapier-alternatives and n8n-alternatives
* feat(landing): extend enterprise product-preview design to solutions and workflows pages
Parametrize enterprise feature graphics with content props and retell each
solutions page's feature blocs for its domain (engineering, it, compliance,
finance, hr) plus the workflows platform page. Add five new graphics in the
same visual vocabulary, animated platform-UI heroes with domain-specific
loops on all six pages, hero category tags, container-query proportional
tile scaling with wide/2x2 layout options, and a shared pre-footer CTA band.
Enterprise page renders identically.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(landing): surface Platform and Solutions menus in top nav
Renders PLATFORM_MENU and SOLUTIONS_MENU alongside Resources (Platform,
Solutions, Resources trigger order), drops the internal-only Mothership
item, centers the five-item Platform panel's two-tile last row, and lets
the mobile sheet scroll now that all three sections outgrow a phone
viewport.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(landing): add scheduled tasks page and nav item
Adds the /scheduled-tasks landing page (SolutionsPage consumer with a
chat-free schedule-trigger editor hero and enterprise feature tiles
retold for recurring runs) and a sixth Scheduled Tasks item in the
Platform menu, restoring the clean 3x2 grid.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(landing): add knowledge, tables, files, and logs platform pages
Completes the Platform nav dropdown — its knowledge, tables, files, and
logs items previously 404'd. Each page is a SolutionsPage consumer with a
product-UI hero loop, enterprise-style feature tiles, CTA band, and SEO
metadata. Removes the dead platform-page component family (workflows was
its last consumer) and adds the new routes to the sitemap.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(landing): consolidate hero-loop engine and code-window graphics, drop dead variant surface
- Extract shared useDesignScale + useMotionSafeCycle hooks and a HeroLoopShell
so all seven hero loops share one scale/reduced-motion clock engine
- Merge workflows-editor-loop and scheduled-tasks-hero-loop into one
parameterized shared EditorLoop (content-injection, same pattern as
EnterpriseLoopContent)
- Consolidate the four identical code-window feature graphics into one shared
CodeWindowGraphic + single CSS module; pages keep thin data wrappers
- Remove the unreachable 'split'/'standard'/align variant surface from
SolutionsPage/SolutionsCardRow/SolutionsCard and trim unused barrel re-exports
- Enterprise hero now consumes the shared PlatformHeroVisual instead of an
inline byte-identical copy
- Add /scheduled-tasks to the sitemap
- a11y: closed mobile-nav sheet is now invisible (out of tab order) with
aria-controls wiring; decorative tables-hero checkboxes are no longer
keyboard-focusable
- memo() the static EnterpriseSidebar; hoist per-render header arrays; remove
comments that restated component TSDoc
* fix(landing): highlight Scheduled tasks in the scheduled-tasks hero sidebar
Thread activeNav through the shared EditorLoop content so the
scheduled-tasks hero highlights its own module row, matching the other
platform heroes.
* chore(landing): drop spacing constants orphaned by the variant removal
Remove the now-unconsumed cardRowHeaderStack/cardRowHeaderCtaGap/
cardTextToVisual/rowSubtitle constants, fix a stale cardVariant TSDoc
reference, and restore import order in the workflows editor-loop wrapper.
* chore(landing): single-source RESET_FADE_MS and drop the unused card frame size
RESET_FADE_MS now lives only in the shared loop-engine hook module; the
enterprise stage-data copy is removed. SolutionsVisualFrame loses its
size prop and cardHeight constant - only the 16:9 hero preset remained
in use after the split-variant removal.
* fix(landing): make the knowledge-answer question bubble visible on light tiles
The frameless vignette sits directly on the tile's --surface-3 fill, so
the build tile's --surface-3 bubble treatment vanished. The question
chip now uses the graphic family's white card chrome (--white fill,
--border-1 hairline), matching its own source card. Also restores
biome's import order in the workflows editor-loop wrapper (fixes the
failing lint:check CI step).
* chore(landing): share one ZipIcon across the files preview and files hero
Extract the duplicated zip-archive SVG into components/shared/zip-icon
and consume it from both the homepage files preview and the files hero
loop.
---------
Co-authored-by: andresdjasso <andresdjasso@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Waleed Latif <walif6@gmail.com>
* fix(tools): resolve {{ENV_VAR}} references in user-only params for copilot tool executions
Chat-invoked integration tools with API-key auth have been broken since the
mothership tool-dispatch rewrite (#4090) removed the orchestrator's env
reference resolution. Agents pass {{VAR}} references (the VFS exposes env var
names only), and the literal placeholder was sent to the provider, producing
auth failures like Sentry's 401 Invalid token.
Resolution is deliberately narrower than the removed deep resolver: only
whole-value references on params declared visibility user-only, gated to
copilot executions, resolving against the same personal+workspace env merge
workflow runs use. LLM-writable params (urls, headers, bodies) never resolve,
so references cannot be used to extract secrets. Missing variables fail fast
with an actionable error instead of a provider-side 401.
* refactor(tools): delegate copilot env reference resolution to the shared executor resolver
Replaces the hand-rolled exact-match regex with resolveEnvVarReferences
(allowEmbedded: false), the same resolver used by workflow runs, MCP config,
and webhooks — one set of reference semantics instead of two that can drift.
Behavior is identical; all existing tests pass unchanged.
* fix(tools): fail fast on env references without user context, clarify personal-only scope errors
Addresses review: a copilot execution missing userId now errors explicitly
instead of forwarding the literal placeholder upstream, and a missing-variable
error without a workspace context explains that only personal variables are
in scope there (matching workflow-run resolution semantics).
* feat(billing): allow programmatic workflow execution on the free plan
Remove the free-plan paywall on programmatic execution (API-key/public
execute, MCP serve, generic webhooks, cross-origin chat embeds) added in
#5036. The gate shipped dark behind FREE_API_DEPLOYMENT_GATE_ENABLED to
curb bot abuse; with that abuse handled upstream, free workspaces can use
the API again (still subject to the free-tier rate limits).
- Delete isWorkspaceApiExecutionEntitled / api-access.ts and the
FREE_API_DEPLOYMENT_GATE_ENABLED env flag
- Ungate the execute, mcp/serve, and webhooks/trigger routes and the chat
embed check (assertChatEmbedAllowed removed)
- Remove the deploy-modal upgrade wall (DeployUpgradeGate) and the now
unused useWorkspaceOwnerBilling client hook; the owner-billing endpoint
stays as reusable billing infrastructure
- Restore pre-gate upgrade-page copy (Pro feature line, free API endpoint
rate-limit column)
* chore(billing): drop orphaned owner-billing endpoint and dead chat logger
Self-review follow-ups: the /api/workspaces/[id]/owner-billing route +
contract existed solely for the deploy-modal gate's client hook (deleted
here); host-context serves the same ownerBilling data server-side, so the
standalone endpoint is dead HTTP surface. workspaceOwnerBillingSchema and
the WorkspaceOwnerBilling type stay (embedded in workspaceHostContextSchema).
Also removes the now-unused ChatAuthUtils logger.
* style: biome formatting after gate removal
* improvement(chat): show resource-type icons on inline workspace resource links
* fix(chat): derive wsres click title from markdown label, not DOM textContent
* fix(chat): keep dashed-underline affordance for unmapped wsres link types
* fix(chat): parse wsres links once, derive file icons from the VFS path
* fix(custom-blocks): reserve system output names and hide own block from command modal
* fix(mothership): constrain custom block image icons in subagent tool rows
* improvement(custom-blocks): allow result as an exposed output name
* fix(landing): align author-page UI with the site shell and link bylines to it
Rebuilds ContentAuthorPage/ContentAuthorLoading to match the standard
page-shell pattern used by ContentIndexPage/ContentPostPage (max-w-[1460px]
header, BackLink, framed post-list rows with hover states) instead of the
previous bare max-w-[900px] container with a 2-column image grid. Adds a
styled not-found fallback matching the comparisons/integrations pattern.
The byline author Link in ContentPostPage now points at the internal
author page (/{basePath}/authors/{id}) instead of the author's external
X/GitHub profile, giving the author page a real navigation entry point for
the first time - previously it was only reachable via the sitemap.
Also fixes both author-page route files to match on any of a post's
authors (post.authors.some(a => a.id === id)) instead of only the primary
author (post.author.id === id), so posts with co-authors show up on every
listed author's page, consistent with the sitemap's own author enumeration.
* fix(landing): address review findings on author-page UI rebuild
- Not-found fallback no longer renders a nested <main id='main-content'>
- blog/layout.tsx and library/layout.tsx already provide that landmark,
so the fallback now uses <section> like the rest of the component.
- Byline author link now encodeURIComponent()s the author id before
using it as a route segment.
- Loading skeleton's post-list wrapper now matches the real page's
mx-auto max-w-[1460px] shell (was mx-20/max-lg:mx-8, which stretches
past the header on wide viewports).
* fix(landing): make author Person.image an absolute URL in JSON-LD
Same class of bug as the earlier article-image fix: author.avatarUrl is a
site-relative path, so Person.image was emitting an invalid relative URL
for crawlers. Prefixes with SITE_URL, matching buildArticleJsonLd's
existing pattern.
* fix(landing): align author not-found fallback width with the site convention
max-w-[1446px]/px-12 was copied from comparisons/not-found.tsx, which turns
out to be the outlier - models/not-found.tsx and integrations/not-found.tsx
both use max-w-[1460px]/px-20, matching the rest of the site's shell and
this component's own success-state header.
* fix(landing): encode author id consistently in every author URL builder
The byline link encoded the author id, but buildAuthorMetadata's canonical
URL, buildAuthorGraphJsonLd's Person.url/BreadcrumbList item, and
sitemap.ts's buildAuthorPages URL still interpolated the raw id - a
mismatch could point sitemap/canonical/structured-data URLs at a
different route than the actual page. All four now encodeURIComponent()
consistently.
* improvement(url-state): migrate list search/sort/filter view-state to nuqs
* fix(url-state): clear mcpServerId selection when the selected workflow MCP server is deleted
* fix(url-state): resolve-gated MCP server detail view + replace-on-close for detail back navigation
* fix(url-state): explicit Suspense boundary for account settings sections
Aligns with the /integrations/[slug] convention (plural category, singular
item). Adds a 301 redirect (both the bare hub page and every competitor
detail page) so previously indexed URLs keep working, and updates every
internal reference: footer nav, sitemap generation, and all import
specifiers/canonical URLs/breadcrumb JSON-LD within the route itself.
Adds the three fields intentionally omitted from #5638 pending real values:
- legalName: 'Sim, Inc' - matches the entity named throughout the Terms of
Service (apps/sim/app/(landing)/terms)
- foundingDate: '2025'
- address: real registered office (80 Langton St, San Francisco, CA 94103)
* improvement(buffer): explicit mediaType override; error instead of guessing on ambiguous media
* fix(buffer): forward validated mediaType from routes into the media resolver
* fix(buffer): presign uploaded media for 7 days — Buffer fetches assets at publish time
* docs(buffer): document presign lifetime bound by signing credentials
* fix(buffer): always mint fresh presigned URLs from verified storage keys for media
* feat(flint): add Flint integration with agent task tools, block, and docs
* fix(flint): forward explicit publish=false, guard missing taskId, align default params branch with tool fallback
* docs(flint): add manual intro section to integration docs page
* fix(flint): fail get_task on OK responses without a task ID
* fix(flint): drop json-object generation type so the wand emits the pages array
* feat(buffer): add Buffer integration with posts, channels, and ideas
* fix(buffer): return clear tool error when account lookup yields no account
* fix(buffer): default schedulingType server-side so basic-mode blocks never fail validation
* fix(buffer): probe Content-Type for extensionless media URLs so videos are not sent as images
* feat(buffer): add get_ideas and get_idea_groups tools, harden media URL classification
* fix(buffer): guard missing post on PostActionSuccess responses
* fix(landing): complete Organization schema, add CollectionPage/BlogPosting JSON-LD, fix TechArticle rich-result eligibility
- Organization schema (site-structured-data.tsx): add brand and
contactPoint.url (verified against the real /contact route); all other
fields were already correct and verified against the Footer's sameAs
links. foundingDate/legalName/address omitted — not verifiable from
anything in this repo.
- CollectionPage (blog + library index): buildCollectionPageJsonLd now
takes the real posts list (same getAllPostMeta() the index page already
renders from) and emits a mainEntity ItemList of BlogPosting stubs
instead of omitting mainEntity entirely.
- BlogPosting + TechArticle (post detail template): Google's Article
rich-result eligibility only recognizes Article/NewsArticle/BlogPosting
— a bare TechArticle type isn't in that allowlist. buildArticleJsonLd
now emits a multi-type @type array (["BlogPosting","TechArticle"]) for
genuinely technical posts, and "BlogPosting" alone for posts that are
general announcements, via a new `technical` frontmatter flag (defaults
true; set to false on the series-a funding-announcement post, the one
post with no technical content). Also fixed a real markup/schema
mismatch: the article's `speakable.cssSelector` referenced
`[itemprop="description"]`, but no element carried that itemProp —
added it to the description paragraph. TechArticle/BlogPosting image
URLs are now made absolute (previously relative paths, invalid for
crawlers).
- FAQPage: audited every LandingFAQ usage (/models, /models/[provider],
/models/[provider]/[model], /integrations, /integrations/[slug],
/comparison, /comparison/[provider]) — all already emit matching
FAQPage JSON-LD sourced from the same data passed to LandingFAQ; no
gaps found, no changes needed.
* fix(landing): match microdata itemType and scope collection JSON-LD to visible posts
Address Greptile/Cursor review on PR #5638:
- itemType now always resolves to BlogPosting (matching Greptile's exact
suggested fix), since the JSON-LD graph already carries the richer
TechArticle type via a multi-type array and the microdata path doesn't
need to duplicate that distinction
- buildCollectionPageJsonLd now receives the same tag-filtered/paginated
post subset ContentIndexPage actually renders, instead of the full
unfiltered catalog, via a new shared selectVisiblePosts/paginateContentPosts
helper in lib/content/index-list.ts (also de-duplicates the pagination
logic that previously lived only in ContentIndexPage)
* fix(landing): match CollectionPage ItemList order and url to the visible filtered/paginated variant
Address round-2 Cursor Bugbot findings on PR #5638:
- buildCollectionPageJsonLd no longer re-sorts the given posts by date -
ordering is now solely owned by the caller (selectVisiblePosts), so
featured-row-first render order matches ItemList position order
- buildCollectionPageJsonLd now takes an optional {tag, page} filter
descriptor and reflects it in the emitted url, instead of always
pointing at the bare section index regardless of which filtered/
paginated variant's posts are actually listed in mainEntity
* feat(gong): align tools with official API spec, add ask-anything, brief, unassign, and logs tools
- fix gong_list_flows: query param was flowEmailOwner (typo copied from Gong's endpoint prose); the API requires flowOwnerEmail, so every call failed
- create_call: drop phantom url output (API returns only requestId/callId) and make downloadMediaUrl optional per spec
- list_scorecards: refresh to current spec (numeric IDs, questionType/answerGuide/minRange/maxRange/answerOptions, reviewMethod)
- answered_scorecards: map selectedOptions on answers, correct score range description (1-50)
- surface requestId uniformly across all read tools; totalRecords no longer fabricated from page size
- normalize includeAvatars to a strict boolean param, uppercase aggregationPeriod, encode userId path param
- validate email/phone format before irreversible GDPR purge calls
- new tools: gong_ask_anything, gong_get_brief (AI entity Q&A/briefs), gong_unassign_flow_prospects, gong_get_logs
* fix(gong): require custom-range dates and gate param remapping by operation
- ask_anything/get_brief: entityFromDateTime/entityToDateTime now conditionally required (UI) and validated tool-side when timePeriod is CUSTOM_RANGE
- block params mapper: remaps are gated by the selected operation so stale values from previously configured operations can no longer overwrite fromDateTime/fromDate/workspaceId
* fix(gong): final spec-alignment pass, review fixes, and regenerated docs
- ask_anything/get_brief: send fromDateTime/toDateTime only for CUSTOM_RANGE; declare mcpResult brief section field
- unassign: dedicated optional unassignFlowId subblock so a stale assign-flow ID can never silently narrow an unassign to one flow
- get_logs: logType is a closed enum (AccessLog, UserActivityLog, UserCallPlay, ExternallySharedCallAccess, ExternallySharedCallPlay) - dropdown in block, enumerated in tool description
- get_folder_content: folderId optional per spec; get_call: encode callId path param
- list_trackers: drop saidInCallParts (absent from the spec's KeywordTracker schema)
- get_extensive_calls: correct declared interactionStats item shape to {name, value}
- block inputs: list all remapped subblock params; optional flags on nullable outputs; absolute types re-export
- regenerate Gong integration docs and integrations.json entries (29 operations)
* feat(library): add n8n alternatives, LangGraph alternatives, and open-source AI agent platform listings
* fix(content): declare actual OG image dimensions instead of hardcoded 1200x630
* fix(landing): fix oversized HTML and severe LCP on integration/comparison pages
Google Search Console flagged /integrations, /integrations/slack, and
several others for exceeding Googlebot's 2MB uncompressed-HTML crawl
limit, plus severe LCP on /integrations, /integrations/slack,
/integrations/hubspot, /comparison/flowise, and /integrations/hugging-face.
Root cause 1 - /integrations/slack was 5.2MB (measured on production).
The "Agent templates" section renders every template matching
getTemplatesForBlock(type) with no cap - Slack is referenced as
alsoIntegrations in 445 templates (vs 52-126 for Salesforce/Gmail/
HubSpot), so its detail page embedded hundreds of full template cards
in the initial HTML/RSC payload. Capped to 12, consistent with the
same file's existing related-integrations cap of 4.
Root cause 2 - /integrations was 1.83MB, right at the limit. The client
IntegrationGrid component receives the full Integration[] as props
(needed for instant client-side search), which serializes every
integration's complete operations/triggers arrays - including full
per-operation description sentences - into the initial payload purely
to build a search index. Added IntegrationSummary + toIntegrationSummary
(lib/integrations): the same searchable surface (name, description,
operation names, trigger names) precomputed server-side into one
lowercased string, dropping the full operations/triggers data the
client never actually renders. Measured: 627KB -> 142KB of embedded
integration data (77% reduction).
Verified via a real production build + curl:
- /integrations: 1.83MB -> 1.31MB
- /integrations/slack: 5.2MB -> 355KB (93% reduction)
- /integrations/hubspot: 901KB -> 452KB
Verified via Lighthouse (mobile, devtools throttling, matching what
real users on a typical device experience) against both live production
and the fixed local build:
- /integrations: 47 -> 96 (LCP unmeasured->2.1s, TBT 2,770ms->110ms)
- /integrations/slack: 47 -> 96 (LCP 9.7s -> 1.9s)
- /integrations/hubspot: 72 -> 97 (LCP 9.1s -> 1.9s)
- /integrations/hugging-face: 72 -> 95 (LCP 9.2s -> 2.3s, reproduced
twice on production before fixing - not a fluke)
- /comparison/flowise: 71 -> 95 (LCP 9.8s -> 2.1s)
The last two aren't Slack-style template-count outliers (4 and 0
alsoIntegrations references respectively) - shrinking the shared
IntegrationGrid client bundle appears to have reduced a shared chunk
loaded broadly across landing pages, benefiting pages beyond the ones
directly touched.
Also checked and confirmed already healthy, no action needed:
/integrations/salesforce, /integrations/gmail, /integrations/amazon-dynamodb,
/comparison/tines, /models/xai/grok-4-20-multi-agent-0309.
* fix(landing): restore full-fidelity search and template priority
Two real regressions from the previous commit, both confirmed by
Greptile and Cursor Bugbot independently:
- lib/integrations: IntegrationSummary.searchText joined every field
into one string, so (a) it dropped operation/trigger descriptions
entirely (a search for API-specific terms that only appear in an
operation's description, not its name, silently stopped matching),
and (b) a single joined string lets a query span a field boundary
(e.g. matching across the tail of a name and the head of the next
field) that the original per-field search never allowed. Reverted to
a searchFields array - same content as the original per-field index
(name, description, every operation's name+description, every
trigger's name), just precomputed server-side instead of shipping
the full Integration objects. Grid filtering goes back to
`.some(field => field.includes(q))`, matching the exact original
matching semantics.
- blocks/registry.ts + integrations/[slug]/page.tsx: capping
getTemplatesForBlock's result with a plain .slice(0, 12) kept
whatever 12 templates happened to iterate first in registry
insertion order - for a high-connectivity integration like Slack,
that can be entirely alsoIntegrations matches from unrelated blocks,
silently dropping the integration's own owned templates and any
marked featured. Added an explicit isOwner flag to
ScopedBlockTemplate (the registry function already computes this
internally, just wasn't surfacing it) and sort owner-first,
featured-second before slicing.
* fix(landing): sort featured templates ahead of owned, not just as a tiebreaker
The previous sort (owner-first, featured as a tiebreaker within each
owner tier) meant an integration with 12+ owned templates filled the
entire cap with non-featured owned templates before any featured
related template (reached via alsoIntegrations) was ever considered -
Slack hits this case. Swapped the sort so featured (owned or related)
ranks first, then owned-but-not-featured, so a curated featured
template can no longer be sliced away by a pile of ordinary owned ones.
Google Search Console flagged every /models/{provider}/{model}/opengraph-image
and /integrations/{slug}/opengraph-image URL as 404 (~230 pages total: 5
sample model pages plus ~130 more models, plus every integration).
Root cause: the sibling page.tsx for each of these routes sets
`dynamicParams = false`, a segment-level restriction that also blocks
the metadata route (opengraph-image.tsx) from rendering any param
combination it wasn't statically told about - but Next does not share
generateStaticParams between a page and its sibling metadata routes.
Since none of the three opengraph-image.tsx files exported their own
generateStaticParams, every param was "unknown" to that restriction and
404d, for every single model and integration.
Added a matching generateStaticParams to all three files, mirroring
each route's own page.tsx.
Note: the exact URLs in the audit report (bare /opengraph-image, no
suffix) aren't the real ones - Next serves these at a build-generated
hash suffix (e.g. /opengraph-image-15dal5?<hash>), which is what's
actually embedded in each page's <meta property="og:image"> tag. The
underlying bug the report surfaced is real regardless; verified by
requesting the actual hash-suffixed URL each page embeds (previously
404, now 200) for both a model and an integration page, on a real
production build.