v0.7.7: square, context.dev integrations, scheduled tasks styling changes, code hygiene#5064
Conversation
* feat(context-dev): add Context.dev web + brand data integration * feat(context-dev): add brand variants, products, fonts, styleguide, images, prefetch Expands coverage to all relevant Context.dev endpoints (22 tools): brand by name/email/ticker, simplified brand, transaction identifier, single + catalog product extraction, fonts, styleguide, image discovery, and prefetch utilities. Shared brand output schema and transform helper; verified against the live API. * fix(context-dev): wire includeFrames, split crawl/extract maxPages, derive screenshot MIME Addresses review feedback: - includeFrames is now a block subblock + param for scrape_markdown/scrape_html - crawl and extract use separate Max Pages fields (crawl 1-500, extract 1-50) so a crawl value can no longer be forwarded to extract beyond its limit - screenshot file MIME type and extension are derived from the returned URL instead of being hardcoded to PNG
#5050) Socket.io authorized workflow access only at join and cached the workspace role in presence, so a removed or downgraded collaborator kept live read/ write access until they disconnected. - Re-validate the cached role against the permissions table on mutating events, bounded by a short TTL; refresh or evict on change - Add /api/permissions-updated so the app reconciles active rooms, evicting revoked users (cross-pod) and refreshing downgraded roles - Notify realtime on workspace member removal and permission changes
* refactor(executor): collapse subflow node-ID logic behind a codec Extract the ~20 scattered subflow node-ID parsing/building helpers and their regex patterns into a single SubflowNodeIdCodec. All patterns now live in one place; subflow-utils and execution state delegate to it. Pure refactor — byte-identical output, ordering, and error modes. * refactor(providers): extract StreamingExecution assembly into a factory The near-identical streaming-response assembly (timing segments, cost, token counts, onComplete wiring, success/logs/metadata envelope) that was copy-pasted across ~16 providers now goes through createStreamingExecution. Each provider injects only its stream iterable and delta extractors. Gemini is intentionally left as-is (its assembly is structurally divergent). Pure refactor — identical StreamingExecution shape, cost, tokens, timing, and callback order per provider. * refactor(providers): dedupe tool-schema wrapping into adapters Replace the identical inline tool-schema literals repeated across ~16 providers with shared adaptOpenAIChatToolSchema / adaptAnthropicToolSchema helpers. Content building reverts to calling the attachments builders directly (the per-provider content seam was pure pass-through indirection). Pure refactor — byte-identical tool-schema and content output. * chore(skills): point add-model provider edits at shared response/tool-schema helpers When editing provider code, reuse createStreamingExecution and the tool-schema-adapter helpers instead of hand-rolling. * refactor(providers): drop placeholder stream double-cast in streaming factory Build the output object before creating the stream so the factory returns a fully-typed StreamingExecution without 'undefined as unknown as ReadableStream'. Keeps the strict API-validation boundary ratchet green (double-cast count back to baseline). No behavior change: the same output reference is mutated on drain.
* feat(square): add Square integration with 34 commerce operations Add a Square integration (API-key auth via personal access token) covering payments, refunds, customers, locations, orders, invoices, catalog, and inventory. Catalog image upload routes through an internal API endpoint using the shared UserFile handling pattern. Adds a dedicated square-errors extractor. * fix(square): correct catalog image part name and address review feedback - Fix catalog image upload: Square's multipart part for the binary is `file`, not `image_file` (per the live API cURL examples); this would have caused upload failures - Catalog image route: check response.ok before parsing, drop the unreachable legacy base64 path, derive MIME from the uploaded file - Block: split the search query field per operation so placeholders match each endpoint's schema; parse each JSON field individually so errors name the field - Round out coverage: complete_payment version_token; customer nickname/birthday; batch inventory states/updated_after/limit * fix(square): correct canonical file param usage and revert query split - Read the catalog image file from the canonical `params.file` (the basic/advanced inputs are collapsed before the params function runs) instead of the raw uploadFile/fileRef ids, which no longer exist at that point — fixes the Canonical Param Validation test and a latent upload bug - Revert the per-operation query split: canonicalParamId is only valid for basic/advanced pairs under one condition. Use a single query field with a schema-neutral placeholder and a wand prompt that covers each search operation * chore(square): trigger fresh review * fix(square): single-location invoice search and guard numeric coercion - SearchInvoices: Square's invoice filter accepts only one location, so take a single locationId (string) instead of an array and wrap it as query.filter.location_ids: [locationId] - Block: fail locally with a clear "<field> must be a valid number" error when amount/limit/version/orderVersion are non-numeric instead of forwarding NaN * fix(square): accept real booleans for autocomplete/includeRelatedObjects Coerce these from both the dropdown's string values and actual booleans (which can arrive via connected blocks or templated inputs), so true is not silently flipped to false. * fix(square): validate parsed JSON field shapes (array vs object) parseJsonField now enforces the expected shape so a valid-but-wrong-type value (e.g. a JSON string where an array is expected for locationIds/objectTypes/ paymentIds/catalogObjectIds/states, or a non-object for order/invoice/etc.) fails locally with a clear message instead of a confusing Square API error.
…ction (#5054) * improvement(scheduled-tasks): move recurrence into modal body as a section Replace the footer RecurrenceControl (a row of chip dropdowns) with a RecurrenceSection rendered between the prompt body and footer: a "Recurring" Switch toggles one-time vs repeat, and — once on — frequency and end (never, on a date, after N runs) are labeled ChipModalField rows aligned to the modal header/footer gutter. Toggling Recurring off now preserves the recurrence shape (cadence, end, and a passed-through custom cron) and only sets frequency: 'once', so toggling back on restores a conversationally-authored custom schedule instead of silently rewriting it to daily. Also restore the prompt editor's native scale (text-[15px], -0.015em tracking) so the editor reads the same in the chat input and the task modal body. * fix(scheduled-tasks): clear custom cron when switching frequency away from custom The Recurring toggle restores `frequency: 'custom'` when `recurrence.cron` is truthy, but switching the frequency dropdown away from custom kept the stale cron on the object — so editing a custom-cron task to Daily, then toggling Recurring off and back on, snapped it back to Custom and persisted the old cron. Clear `cron` in the non-custom frequency branches so it is present only while the cadence is genuinely custom (matching the type's "custom only" invariant), making the toggle's restore signal accurate. Also document the unreachable `once` branch in frequencyOptionFor as a type-exhaustiveness fallback (keeps the return type without a cast). * fix(scheduled-tasks): restore the prior cadence when re-enabling recurrence Toggling Recurring off collapsed frequency to 'once' but toggling back on forced 'daily' and cleared weekdays, so pausing a weekly/weekdays/monthly task and re-enabling it silently reset it to daily. Cache the last recurring cadence in a ref (written during render) and reinstate it on toggle-on, so a paused "Weekly on Mon" returns as weekly. This also subsumes the custom-cron restore — the ref remembers 'custom' across the one-time interval — so the toggle no longer special-cases cron. * improvement(scheduled-tasks): compose canonical modal separator, tidy imports Replace the recurrence section's hand-rolled `h-px bg-[var(--border)]` divider with the canonical ChipModalSeparator (now exported from the chip-modal barrel) so the modal's hairline has a single source of truth. Also unify loading.tsx icon imports onto the @/components/emcn barrel. --------- Co-authored-by: waleed <walif6@gmail.com>
* feat(mothership): add enrichment_run server tool for one-off lookups Implement the Sim-side handler for the copilot enrichment_run tool: runs the enrichment provider cascade for a single entity and returns the result inline, surfacing the hosted-key cost as _serviceCost for per-round billing (matching the media tools). Registered in the server-tool router. Regenerate the copilot tool catalog/schemas to include enrichment_run. * fix(mothership): remove leftover touch_plan tool references touch_plan was removed from the copilot tool catalog earlier, but the Sim side still referenced it. Regenerating the generated tool catalog (for enrichment_run) synced it to the current contract and dropped the stale TouchPlan export, which broke the build where router.ts still imported it. Remove the dead touch_plan server tool and its test, drop its router registration and WRITE_ACTIONS entry, simplify getServerToolRegistry (no more beta-gated server tools), and clean up stale "use touch_plan" guidance strings. * chore(mothership): trigger dev redeploy * improvement(mothership): log billed cost on enrichment_run lookups
* feat(mothership): add enrichment_run server tool for one-off lookups Implement the Sim-side handler for the copilot enrichment_run tool: runs the enrichment provider cascade for a single entity and returns the result inline, surfacing the hosted-key cost as _serviceCost for per-round billing (matching the media tools). Registered in the server-tool router. Regenerate the copilot tool catalog/schemas to include enrichment_run. * fix(mothership): remove leftover touch_plan tool references touch_plan was removed from the copilot tool catalog earlier, but the Sim side still referenced it. Regenerating the generated tool catalog (for enrichment_run) synced it to the current contract and dropped the stale TouchPlan export, which broke the build where router.ts still imported it. Remove the dead touch_plan server tool and its test, drop its router registration and WRITE_ACTIONS entry, simplify getServerToolRegistry (no more beta-gated server tools), and clean up stale "use touch_plan" guidance strings. * chore(mothership): trigger dev redeploy * improvement(mothership): log billed cost on enrichment_run lookups * fix(contracts): regenerate mship contracts * fix(contracts): fix mship contracts
…#5061) * feat(utils): add record guards and pure helpers to @sim/utils Add isRecordLike (loose, non-prototype-checked record guard) and sortObjectKeysDeep; relocate isPlainRecord (strict) and normalizeEmail into @sim/utils so they are reusable across apps and packages. Unit tests cover the loose-vs-strict distinction, deep key sorting, and email normalization. * refactor(sim): consolidate record guards and normalize helpers onto @sim/utils Replace ~55 re-implemented loose record guards with the canonical @sim/utils isRecordLike (and one strict site with isPlainRecord), and dedupe three normalize clusters: sortObjectKeysDeep (sanitization + copilot builders), normalizeToken (salesforce + servicenow triggers), and normalizeEmail. Array-allowing guards and domain-specific normalizers are intentionally left untouched. Pure refactor — identical predicates and transforms, no behavior change.
… plan (#5055) * fix(billing): deploy modal gates on workspace entitlement, not viewer plan The deploy modal showed the upgrade wall to a free user in a PAID workspace, because it gated on the viewer's individual plan (useSubscriptionData) while the server gates on the workspace billed account (rolled-up plan). Add a workspace api-execution-entitlement endpoint that mirrors isWorkspaceApiExecutionEntitled, and gate the API/MCP/A2A tabs on it so the UI matches the server exactly. * fix(billing): key deploy gate on URL workspaceId + refetch entitlement on open Address review findings: - key useWorkspaceApiExecutionEntitlement on the URL workspaceId (available on mount) instead of workflowWorkspaceId (null until the workflow map resolves), so the gate fires immediately instead of leaving the tabs ungated until then - staleTime 0 so reopening the deploy modal refetches entitlement; a plan upgrade happens outside this query's invalidation graph, so the gate self-heals on open * refactor(billing): workspace owner access state instead of bespoke entitlement endpoint Replace the single-purpose api-execution-entitlement endpoint with a reusable workspace-owner billing/access concept — the workspace-scoped counterpart to the viewer-scoped useSubscriptionData: - getWorkspaceOwnerSubscriptionAccess(workspaceId): the billed account's rolled-up subscription access fields (mirrors getSimplifiedBillingSummary's flag derivation) - GET /api/workspaces/[id]/owner-billing + useWorkspaceOwnerBilling hook - deploy modal derives its gate via the existing getSubscriptionAccessState (hasUsablePaidAccess) on the owner data, exactly like every other paid feature Audited the rest of the app: no other UI gates on the viewer's plan where the server gates on the workspace owner — programmatic execution is the only workspace-owner-scoped feature; inbox/KB-live-sync/credential-sets all gate consistently on both sides. * fix(billing): deploy gate on owner isPaid, not hasUsablePaidAccess hasUsablePaidAccess rejects past_due and billing-blocked, but the server gate (isWorkspaceApiExecutionEntitled) allows any paid plan in an entitled status (active or past_due). Gate on the owner's isPaid so a past_due paid workspace isn't shown the upgrade wall while the API still works.
…5062) * fix(execute): block cross-origin session-authenticated workflow runs * fix(execute): scope session origin guard to provable cross-origin Address review on #5062: - Reject session-cookie execution only when provably cross-origin (Sec-Fetch-Site cross-site/same-site/none, or a mismatched Origin) instead of failing closed on absent headers. Fixes route tests that 403'd on header-less session requests, and reflects that this is CSRF protection, not anti-cookie-replay. - Drop same-site from the trusted set: only same-origin is our front-end. - Guard the Origin fallback in try/catch so a getBaseUrl() throw can't escape. - Add a route-level cross-origin rejection test.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Deploy modal billing no longer keys off the viewer’s subscription: it calls new Hygiene refactors move Scheduled tasks UI replaces footer Reviewed by Cursor Bugbot for commit d89824c. Bugbot is set up for automated code reviews on this repo. Configure here. |
Uh oh!
There was an error while loading. Please reload this page.