Commit Graph
4370 Commits
Author SHA1 Message Date
WaleedandClaude Opus 4.7 ceb7d20aed fix(docker): use full bun.lock + bump deprecated GHA actions (#4323)
* fix(docker): use full bun.lock and copy it into builder

The staging build for app.Dockerfile (commit dc2022995, PR #4322) is
failing in two ways after switching to turbo prune:

1. turbo 2.9.6's pruned bun.lock is malformed for bun 1.3.x:
     error: Failed to resolve prod dependency 'wrap-ansi' for package
     'log-update' at bun.lock:2688:5
   Bun ignores it and falls back to a fresh resolve (~7m install).

2. Next.js 16.1.6's Turbopack production build can't infer the workspace
   root because /app/bun.lock doesn't exist in the builder stage:
     Error: We couldn't find the Next.js package (next/package.json)
     from the project directory: /app/apps/sim
   This blocks the build entirely.

Fix:
- deps stage: use the full bun.lock from /app/bun.lock (the original
  lockfile after `COPY . .` in pruner) instead of the broken
  /app/out/bun.lock that turbo prune emits.
- builder stage: also copy the full bun.lock to /app/bun.lock so
  Turbopack and turborepo can detect the workspace root.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(ci): bump deprecated Node.js 20 actions to Node.js 24 versions

GitHub Actions runners emit deprecation warnings for actions still on the
Node.js 20 runtime. Node.js 20 will be force-upgraded by GitHub on
2026-06-02 and removed on 2026-09-16.

Bumps to the latest stable major versions, all of which use Node.js 24:

- actions/cache: v4 -> v5
- actions/setup-node: v4 -> v6
- aws-actions/configure-aws-credentials: v4 -> v6
- docker/login-action: v3 -> v4

All require GHA runner v2.327.1+ which Blacksmith already runs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 13:47:36 -07:00
Waleed 6a7d5ae828 feat(files): extract PDF viewer behind SSR boundary and polish file preview (#4316)
* feat(files): extract PDF viewer behind SSR boundary and polish file preview

## Core architectural fix

Move all react-pdf / pdfjs-dist code into a new pdf-viewer.tsx module and
import it exclusively via next/dynamic({ ssr: false }). pdfjs-dist v5
references DOMMatrix at module evaluation time, which crashed SSR. The
previous workaround (a DOMMatrix polyfill in instrumentation.ts) is removed
in favour of this proper hard module boundary.

## PDF viewer improvements

- Cursor-anchored zoom: Ctrl/⌘+wheel and trackpad-pinch now zoom toward the
  cursor instead of the top-left corner. Toolbar ± buttons anchor to the
  viewport centre. Uses the canonical scroll-adjust formula used by map and
  canvas viewers.
- Horizontal scroll: dropping flex-col from the scroll container lets the
  zoomed pages wrapper overflow naturally and produces a horizontal scrollbar
  at zoom > 1×.
- Loading skeleton: replaced the conditional inline skeleton with an
  absolute inset-0 overlay so it fills the scroll container correctly in all
  layout contexts.
- Shadow tokens: fixed shadow-[var(--shadow-medium)] and
  shadow-[var(--shadow-card)] to use the Tailwind utility classes
  shadow-medium and shadow-card directly.

## File viewer cleanup

- data-table.tsx: wrap setInputRef in useCallback([]) so the ref callback
  has a stable identity across renders. Previously the inline function got a
  new identity on every keystroke (because editValue state changed), causing
  React to teardown/remount the ref and re-run node.select() on every
  character typed.
- preview-panel.tsx: keep useMemo on ctxValue passed to Context.Provider —
  Context uses Object.is, so a new object every render causes unnecessary
  consumer re-renders.
- resource-content.tsx: remove unnecessary useCallback/useMemo wrappers on
  handlers and derived values that have no memoization observers.

## API route

- Wrap content route with withRouteHandler for automatic request-ID tracking
  via AsyncLocalStorage; remove manual generateRequestId() calls.
- Add resourceName to audit record; add encoding param support (base64 /
  utf-8).

## Query hooks

- Include key (storage object key) in both useWorkspaceFileContent and
  useWorkspaceFileBinary query key tuples so the cache is correctly busted
  when a file is re-uploaded with a new storage key.

## Other

- Add Suspense boundaries to files/page.tsx and files/[fileId]/page.tsx
  (required for useSearchParams inside the Files component).
- Add mmd to SUPPORTED_CODE_EXTENSIONS (Mermaid diagrams).
- Add https: to CSP img-src.
- Remove ==== separator comments from lib/copilot/constants.ts.
- New dependencies: pdfjs-dist 5.4.296, mermaid 11.14.0,
  monaco-editor 0.55.1, @monaco-editor/react 4.7.0.

* fix(files): replace instanceof Error checks with toError() and fix skeleton tokens

- Use toError() from @sim/utils/errors across all catch blocks in
  file-viewer.tsx, preview-panel.tsx, and route.ts instead of the
  prohibited `err instanceof Error ? err.message : fallback` pattern
- Fix loading skeleton in files.tsx: bg-white → bg-[var(--surface-2)]
  and shadow-[var(--shadow-medium)] → shadow-medium

* fix(files): address PR review findings

- csp.ts: revert bare https: from img-src — it defeats the existing
  domain allowlist and opens info-leakage vectors
- files/page.tsx + files/[fileId]/page.tsx: add explicit fallback={null}
  to <Suspense> to make intent clear (React defaults to null, but
  omitting it looks like an oversight)
- preview-panel.tsx: restore pre passthrough in STATIC_MARKDOWN_COMPONENTS
  so Streamdown's wrapping <pre> doesn't nest inside the custom code
  block <div>, which produced invalid HTML and broken styling
- file-viewer.tsx: add 'webm' to VIDEO_PREVIEWABLE_EXTENSIONS to match
  'video/webm' in VIDEO_PREVIEWABLE_MIME_TYPES

* chore(files): revert accidental pptxgenjs.cjs re-minification

The bundle was regenerated non-deterministically during development (same
pptxgenjs 4.0.1, different variable names in minifier output). No functional
change — restore the prior version to keep the diff clean.

* fix(files): fix Monaco stale closure, XLSX Ctrl+S data loss, and async workbook mutation

Three bugs from Cursor Bugbot follow-up review:

1. Stale closure in handleEditorMount (Medium): useCallback([], []) captured
   content='' at first render. When Monaco mounts after content loads (e.g.
   switching from preview to editor mode), lastSyncedContentRef was never
   initialized and external content changes stopped syncing. Fixed by keeping
   a contentRef updated on every render and reading it inside handleEditorMount.

2. XLSX Ctrl+S discards active cell edit (Medium): handleSave read from
   workbookRef.current before DataTable's in-progress editValue was committed.
   Fixed by exposing commitEdit() from DataTable via useImperativeHandle
   (using an always-current editStateRef so the handle stays stable) and
   calling it at the top of handleSave.

3. Async workbook mutation fragility (Low): handleCellChange / handleHeaderChange
   updated the workbook inside import('xlsx').then(), creating microtask-order
   coupling with handleSave. Fixed by caching the xlsx module in xlsxModuleRef
   on first parse and using it synchronously in both handlers.

* refactor(files): cleanup anti-patterns across file viewer components

Six-pass cleanup over the file-viewer directory:

Effects (you-might-not-need-an-effect):
- AudioPreview, VideoPreview: replace reset useEffect with key={file.id} so
  the component remounts on file change — React's canonical solution
- DocxPreview: same key-prop fix; removes a 5-setState reset effect that was
  also clearing containerRef.current.innerHTML unnecessarily

Callbacks (you-might-not-need-a-callback):
- handleEditorMount, handleEditorChange: remove useCallback — MonacoEditor is
  dynamic(), not React.memo, so reference stability has no observer
- markSavedContent: remove useCallback — called only through an onSaveRef,
  never directly observed
- DataTable.setInputRef: remove useCallback — callback refs on native elements
  are called regardless of reference identity

Design tokens (emcn-design-review):
- VideoPreview: bg-black → bg-[var(--surface-inverted)]
- HtmlPreview iframe: bg-white → bg-[var(--surface-2)]

useMemo, useState, and react-query passes found no issues.

* improvement(files): replace stock Monaco theme with Sim design system theme

Define sim-dark and sim-light Monaco themes using Sim's exact design tokens
instead of the default vs/vs-dark which looked identical to stock VSCode.

Chrome changes (both themes):
- Background, gutter use --bg (not VSCode's near-black / pure-white defaults)
- Line numbers use --text-muted instead of VSCode gray
- Cursor switches to --brand-secondary (#33b4ff)
- Selection highlight is brand blue at 15% opacity
- Scrollbar shadow removed, track uses surface tokens
- Bracket match, word highlight, find match all keyed to brand blue
- Suggestion/hover widgets use --surface-2 / --border tokens
- All hardcoded shadows removed (scrollbar.shadow = transparent)

Syntax token changes (inherit: true — base handles unlisted tokens):
- Comments: muted gray + italic (vs VSCode's bright green)
- Strings: #3ab872 dark / #16825d light (vs VSCode orange-red)
- Numbers: warm amber / warm orange (both readable on their backgrounds)
- Keywords: #33b4ff dark / #0078d4 light (brand blue family)
- Types: complementary blue-gray / purple

* fix(files): bump light theme comment color to #888888 for WCAG contrast

* fix(files): fix dark mode comment contrast #4a4a4a → #606060 (~1.9:1 → ~2.9:1)

* improvement(files): cursor to default color, video background to surface-1

- Monaco cursor: #33b4ff (brand blue) → #e6e6e6 dark / #1a1a1a light
  (text cursor should be neutral, not loud)
- VideoPreview background: var(--surface-inverted) → var(--surface-1)
  (consistent with PDF viewer, fits workspace context over cinema-black)

* fix(files): stabilize setInputRef callback and guard against double-commit in DataTable

Wrap setInputRef in useCallback([], []) so React doesn't tear down and
re-mount the input ref on every keystroke. Without stable identity, every
editValue state change caused node.focus()/node.select() to fire, resetting
the cursor selection to "select all" on each character typed.

Add isCommittedRef to guard both the imperative commitEdit handle and the
inline commitEdit (called by onBlur) against double-application. The ref is
cleared in startEdit and set to true on the first commit, so a concurrent
onBlur cannot re-apply the same edit.

* fix(files): preserve scroll position during Mothership streaming edits

Two fixes to the Monaco auto-scroll logic:

1. At streaming start, initialize textareaStuckRef from the editor's actual
   scroll position (isAtBottom check) instead of unconditionally setting true.
   Previously every streaming session jumped the viewport to the last line on
   the very first content update, even when the user was reading mid-file.

2. Replace the wheel-only DOM listener with editor.onDidScrollChange(), the
   proper Monaco API. This covers trackpad, scrollbar drag, and keyboard scroll
   — not just mouse wheel. As a bonus, scrolling back to the bottom during
   streaming now re-engages follow mode (matching iTerm2/xterm.js behavior).

3. Save and restore view state around model.setValue() during streaming when
   the user has scrolled away from the bottom. This prevents Monaco from
   resetting the viewport on each content replacement. When the user is at
   the bottom, view state is not saved so Effect 3 can scroll to the new bottom.

* fix(files): fix two scroll logic bugs introduced in previous streaming scroll fix

The prior fix introduced a regression for the "user was at bottom" case and
a false-disengagement bug from programmatic scroll events.

Bug 1 — Effect ordering: all three effects fire on the same render when
isStreamInteractionLocked flips true. Effect 2 called isAtBottom() AFTER
Effect 1 had already called model.setValue(), which grew scrollHeight. The
old "at bottom" scroll position was now 200px short of the new bottom, so
isAtBottom() returned false, textareaStuckRef was set false, and Effect 3
never called revealLine. Users at the bottom stopped following the stream.

Fix: measure isAtBottom() in Effect 1 BEFORE setValue, while scrollHeight
is still accurate. Set textareaStuckRef = true only (never false here).
Effect 2 no longer initializes the ref — only the listener disengages it.

Bug 2 — onDidScrollChange fires during model.setValue: Monaco fires
onDidScrollChange when scroll dimensions change, including when setValue
grows the document. This caused the listener to disengage auto-scroll on
every content update even with no user interaction.

Fix: add suppressScrollListenerRef, set true before setValue/restoreViewState
and false after. The listener exits early when suppressed, so only genuine
user scroll events (wheel, trackpad, keyboard, scrollbar) can disengage.

Both refs moved to the component's ref block for conventional placement.

* chore(files): remove extraneous comments from file viewer and data table

* refactor(files): split 2281-line file-viewer.tsx into focused modules

TextEditor, DocxPreview, PptxPreview, XlsxPreview, ImagePreview each moved
to their own files. Shared utilities (PreviewError, resolvePreviewError,
shouldSuppressStreamingDocumentError, PDF_PAGE_SKELETON) extracted to
preview-shared.tsx. file-viewer.tsx is now the orchestrator + MIME constants
+ small stateless previews (~495 lines).

* fix(files): remove unnecessary TextEditorProps export

* refactor(files): four stellar-quality improvements to file-viewer split

- Extract useBlobUrl hook shared by AudioPreview and VideoPreview,
  eliminating ~30 lines of duplicated state/effect logic
- Stabilize markSavedContent with useCallback (matches setDraftContent)
- Stabilize handleEditorChange with useCallback([setDraftContent])
- Fix pptx static render effect deps: drop redundant dataUpdatedAt
  (already encoded in cacheKey) and unused workspaceId

* test(files): extract pure modules and add 122-test suite for file viewer logic

Extract TextEditorContentState machine and file category resolution into
plain .ts modules (text-editor-state.ts, file-category.ts) so they can
be unit-tested without React or Next.js overhead. Update component files
to import from the extracted modules, eliminating code duplication.

Add two test files:
- text-editor-state.test.ts: 32 tests covering resolveStreamingEditorContent,
  the reducer (edit / save-success), and syncTextEditorContentState across
  all phases (uninitialized, ready, streaming, reconciling) including
  reference-equality short-circuit checks for zero-allocation paths
- file-category.test.ts: 90 tests covering MIME-type routing for all 8
  categories, extension fallback, MIME-priority-over-extension, and
  case-insensitive extension handling

* fix(files): add key to IframePreview and use monotonic seq for streaming PDF key

- Add key={file.id} to IframePreview so React remounts on file switch,
  preventing stale renderError from persisting across different files
- Replace key={streamingBuffer.byteLength} with a monotonic sequence
  counter so same-size successive PDF compilations still trigger a remount

* fix(files): restore getFileExtension import dropped during refactor

* fix(files): clear loadError on PDF success and fix streaming null-flash

- pdf-viewer: add setLoadError(null) in onLoadSuccess so the toolbar
  is not permanently hidden after a failed-then-successful PDF load
- file-viewer: consolidate streaming-mode rendering so the debounce
  period (before rendering=true) shows a skeleton instead of null

* refactor(files): cleanup pass — effect, callback, state, and design fixes

- text-editor: replace sync-external useEffect with "adjust during render"
  pattern so the state machine advances immediately instead of after a paint
- text-editor: remove unnecessary useCallback from markSavedContent (no observer)
- files: narrow deleteTargetFile state to {id, name} — only those fields are used
- files: remove uploadFile (mutation object) from useCallback deps — .mutateAsync is stable
- files: remove unnecessary useCallback from handleNavigateToFiles (no observer)
- files: replace raw <button> with emcn Button for "Clear all filters" action
2026-04-28 13:07:24 -07:00
WaleedandClaude Opus 4.7 dc20229954 perf(docker): use turbo prune for app.Dockerfile (#4322)
* perf(docker): refactor app.Dockerfile to use turbo prune

Replaces manual workspace package.json copies with `turbo prune sim --docker`,
matching the canonical Vercel/Turborepo monorepo pattern (and the existing
realtime.Dockerfile).

- New `pruner` stage emits `out/json` (manifests + lockfile) and `out/full`
  (sources) for only the packages sim actually depends on.
- `deps` stage installs from the pruned manifest, so cache invalidates only
  when package.json/bun.lock change — not on source edits.
- Drops 24 lines of brittle manual COPYs (one per workspace package).
- Single full install in deps (no --omit=dev) so build-time devDeps like
  tailwindcss/postcss are available — replaces the earlier hotfix that did
  a second install in the builder stage.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(docker): pin turbo to 2.9.6 in pruner stage

Match the version locked in package.json so pruner output is reproducible
across builds.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 13:06:51 -07:00
Theodore Li 69dc2f04b8 fix(mcp): Use SDK web-standard transport for copilot mcp (#4320)
* fix(api): return 499 on copilot mcp user aborts

* fix(mcp): fix copilot mcp response
2026-04-28 16:05:19 -04:00
3afcad2189 fix(short-input): hide selected text to prevent overlay collision (#4318)
* 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(short-input): hide selected text to prevent overlay collision

The ShortInput component uses a transparent input layer beneath a
formatted overlay. When users selected text and scrolled horizontally,
the browser's ::selection pseudo-element overrode `color: transparent`,
making raw unformatted text visible and causing visual collision with
the overlay.

Adding `selection:text-transparent` keeps the input text invisible
under selection, while the overlay continues to display the correctly
formatted highlighted text.

Fixes #3389

Co-Authored-By: Octopus <liyuan851277048@icloud.com>

---------

Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: Theodore Li <theodoreqili@gmail.com>
Co-authored-by: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: Theodore Li <theo@sim.ai>
Co-authored-by: octo-patch <octo-patch@github.com>
2026-04-28 10:57:16 -07:00
WaleedandClaude Opus 4.7 c400e59ea6 feat(sap_s4hana): add get_material_document and fix supplier invoice key order (#4317)
* fix(sap_s4hana): require non-empty items in create_purchase_order

Why: SAP A_PurchaseOrder POST silently fails or returns opaque errors
without to_PurchaseOrderItem entries. Block already required this body
but the tool marked it optional and didn't validate items presence —
mismatched contract with create_sales_order / create_purchase_requisition.

Also clarifies the deliveryDocument placeholder to show both outbound
and inbound number ranges.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(sap_s4hana): add get_material_document and fix supplier invoice key order

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): align material doc key order in description and require purchase order body type

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 23:41:56 -07:00
Vikhyath Mondreti 2e3de9ac8a feat(governance): external workspace users from outside org (#4313)
* feat(governance): external workspace users from outside org

* update docs

* address comments

* edge case improvements

* remove unused fallback

* address comments

* add outbox for seat reduction

* fix edge case with org join after invite

* add server side batch invites for workspace

* use zod schema for route
2026-04-27 22:07:41 -07:00
Theodore Li 154b9d0883 fix(vm): categorize user or server side errors (#4283)
* fix(vm): categorize user or server side errors

* recategorize function syntax errors as 4xx
2026-04-27 22:27:50 -04:00
WaleedandClaude Opus 4.7 c95ac3bc23 improvement(browser-use,stagehand): expose live session URLs (#4314)
* improvement(browser-use,stagehand): expose live session URLs and align with latest API specs

- Browser Use: switch to v2 camelCase schema, fetch live URL from sessions endpoint, add startUrl/maxSteps/allowedDomains/vision/flashMode/thinking/systemPromptExtension/structuredOutput/metadata params, surface liveUrl/shareUrl/sessionId outputs
- Stagehand: fetch Browserbase debug URL, add mode/maxSteps params, surface liveViewUrl/sessionId outputs, bump @browserbasehq/stagehand to ^3.2.1, update to claude-sonnet-4-6

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(browser-use): respect API default for highlightElements

Only send highlightElements when user explicitly toggles it; previously defaulted to true which silently overrode the v2 API default of false.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(browser-use,stagehand): address PR review feedback

- Browser Use: fetch liveUrl during polling once sessionId is known, instead of immediately after task creation. Handles tasks started without profile_id (where sessionId isn't returned in create response) and ensures session is active before fetching.
- Stagehand: coerce empty/whitespace maxSteps strings to undefined so they're dropped from the request body instead of failing zod validation as ''.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(stagehand): preserve liveViewUrl and sessionId on agent error

If the agent throws after Browserbase session init succeeds, callers can still surface the live view / session ID for debugging.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(browser-use): coerce empty maxSteps strings to undefined

Mirrors the Stagehand block's handling so a cleared field doesn't pass through as ''.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(browser-use): skip metadata when empty

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 18:02:51 -07:00
Theodore Li ca814f021d fix(ui): display file upload error messages (#4315)
* fix(ui): display file upload messages

* Address pr comments
2026-04-27 18:58:41 -04:00
WaleedandClaude Opus 4.7 2502369122 feat(integrations): SAP S/4HANA (#4301)
* feat(integrations): SAP S/4HANA tools, block, and proxy with multi-deployment support

* fix(sap_s4hana): address PR review comments

- Validate baseUrl/tokenUrl in Zod schema and at runtime to prevent SSRF
  (https-only, deny loopback/link-local/cloud-metadata hosts)
- Cap proxy token cache at 500 entries with LRU eviction
- Add 30s timeout to outbound token, CSRF, and OData fetches
- Make parseJsonInput return T | undefined so missing input is type-safe
- Reset authType when deploymentType changes and surface OAuth fields
  whenever auth is not basic, so cloud_public users always see clientId/
  clientSecret after switching from a basic-auth private deployment
- Reject OData service names that are not uppercase identifiers and
  paths containing ".." or "." traversal segments

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): allow versioned service names; tighten proxy SSRF defenses

- Permit ";v=NNNN" suffix on ServiceName regex so the four delivery tools
  (API_OUTBOUND_DELIVERY_SRV;v=0002, API_INBOUND_DELIVERY_SRV;v=0002) pass
  schema validation
- Restrict subdomain to RFC 1123 label characters and region to lowercase
  alphanumeric short codes; run the constructed cloud_public host through
  assertSafeExternalUrl so a crafted subdomain (e.g. "evil.com#") cannot
  redirect requests carrying SAP credentials
- Block RFC-1918 (10/8, 172.16/12, 192.168/16), 127/8, 169.254/16, and
  0.0.0.0 via isPrivateIPv4, plus IPv4-mapped IPv6 variants
  (::ffff:10.0.0.1, ::10.0.0.1) so private internal hosts cannot be
  reached from baseUrl, tokenUrl, or the resolved cloud_public URL

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): catch hex-form IPv4-mapped IPv6 in SSRF check

The WHATWG URL parser normalizes IPv4-mapped IPv6 addresses to hex form
(e.g. [::ffff:169.254.169.254] → [::ffff:a9fe:a9fe]), which slipped past
the dotted-decimal-only extractor. Decode the trailing two 16-bit hex
groups back into IPv4 octets and run them through isPrivateIPv4. Also
add isPrivateOrLoopbackIPv6 so pure IPv6 loopback (::, ::1), unique
local addresses (fc00::/7), and link-local (fe80::/10) cannot be reached.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): scope CSRF metadata fetch and isolate token cache by secret

- buildOdataUrl skips request query params when called with an internal
  pathOverride so the /$metadata CSRF probe never carries user OData
  options ($filter, $top, $select), which were causing write operations
  through the generic odata_query tool to fail.
- tokenCacheKey now mixes a sha256 hash of clientSecret into the cache
  key so two tenants sharing the same tokenUrl + clientId but different
  secrets get isolated entries (no cross-tenant token leak).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): reject ?/# in service path; trim long update tool descriptions

- ServicePath validator now rejects "?" and "#" so a caller can't smuggle
  query options through the path field (e.g.,
  "/A_BusinessPartner?$format=atomsvc"); the Zod refine now reports
  ".." / "." segments, "?", and "#" together.
- Update Customer / Update Supplier / Update Purchase Requisition tool
  descriptions exceeded the docs generator's 600-char regex window, so
  they were rendering with empty descriptions on the integrations
  landing page. Trimmed them to fit while keeping the limited-fields
  note and the If-Match guidance, then regenerated integrations.json
  and tool docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): reject percent-encoded path traversal; widen Set-Cookie split

- ServicePath now also rejects %2e/%2E, %2f/%2F, %5c/%5C, %3f/%3F, %23
  so a caller cannot smuggle ".." / "." / "/" / "\" / "?" / "#" past the
  validator and have SAP's ABAP/ICM gateway decode them server-side.
- joinSetCookies fallback regex now allows the ", " separator that's
  used when multiple Set-Cookie values are folded onto one header line
  (older runtimes without Headers.getSetCookie). Prevents CSRF cookies
  from being concatenated into a single value during write operations.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): preserve $ in OData query params; reject empty items array

- buildOdataUrl now constructs query strings manually with
  encodeURIComponent and restores literal "$" so OData system options
  ($filter, $top, $select, $expand, $orderby, $skip, $format) reach
  SAP and any intermediary proxies/WAFs as-is, not as "%24filter".
  URLSearchParams was percent-encoding "$" to "%24" which most ICMs
  decode but some intermediaries silently drop, returning unfiltered
  results.
- create_sales_order now rejects an empty items array (matches
  create_purchase_requisition) so callers get a clear client-side
  error instead of an opaque SAP validation failure on the deep-insert.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): ignore baseUrl on cloud_public to prevent token redirection

Why: resolveHost previously preferred baseUrl unconditionally. A caller
sending deploymentType=cloud_public with a baseUrl pointing elsewhere
would obtain a real SAP UAA token, then forward it as Bearer to the
attacker host. Zod superRefine did not validate baseUrl for cloud_public.

Fix: resolveHost now constructs the SAP host from subdomain when
deploymentType is cloud_public and only uses baseUrl for cloud_private
and on_premise (where it is already SSRF-checked in superRefine).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(icons): use useId for SapS4HanaIcon and PipedriveIcon gradients

Why: hardcoded SVG gradient/mask IDs collide when an icon renders more
than once on a page (e.g. integrations listing). All other icons in this
file use React's useId() — these were inconsistent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* icons

* fix(icons): use useId for AWS-style icon gradients

Why: IAMIcon, IdentityCenterIcon, STSIcon, SESIcon, and SecretsManagerIcon
all used hardcoded `id='xxxGradient'` values that collide when an icon
renders more than once on a page (e.g. integrations listing).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sap_s4hana): ignore tokenUrl on cloud_public to prevent UAA redirection

Why: resolveTokenUrl previously honored caller-supplied tokenUrl
regardless of deploymentType, mirroring the same redirection class as
the prior baseUrl bug. A cloud_public caller could send tokenUrl to an
attacker host, causing the proxy to POST clientId:clientSecret as Basic
auth to it. superRefine for cloud_public did not validate tokenUrl.

Fix: derive UAA URL from subdomain+region for cloud_public; only honor
tokenUrl for cloud_private/on_premise (already SSRF-checked).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(icons): remove unused mask in PipedriveIcon

Why: the <mask> element had no consumer (no mask='url(#...)' anywhere
in the SVG), so both it and the maskId variable were dead code.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 15:07:00 -07:00
Waleed 8266f0afdb fix(security): rate limit chat OTP + validate mothership proxy endpoint (#4312)
* fix(security): rate limit chat OTP endpoint to prevent email bombing

* fix(security): validate mothership proxy endpoint to block path traversal

* fix(security): address greptile feedback on OTP rate limiting
2026-04-27 14:51:58 -07:00
Waleed 896a00ae31 fix(security): require internal API key for copilot training endpoints (#4311) 2026-04-27 14:30:47 -07:00
Waleed 74946fb162 improvement(docker): speed up app image build with cache mounts and parallel node-gyp (#4310) 2026-04-27 13:34:57 -07:00
Waleed f62d274478 fix(mothership): stabilize task sidebar ordering on selection (#4309) 2026-04-27 12:42:20 -07:00
Theodore Li 65e17de065 fix(retention-job): add chunking strategy for cleanup (#4305)
* fix(retention-job): add chunking strategy for cleanup

* change stats to be perjob not per chunk
2026-04-27 15:13:00 -04:00
Vikhyath Mondreti 79ff5d80b3 improvement(slack): channel selector for list canvasses (#4307) 2026-04-27 12:11:14 -07:00
Vikhyath Mondreti 2a52141d2f feat(slack): canvas related operations (#4306)
* feat(slack): canvas related operations

* extract shared code
2026-04-27 12:00:40 -07:00
Theodore LiandClaude Opus 4.7 76ad59fd7d fix(stream): Avoid bun memory leak bug from TransformStream (#4255)
* Avoid bun memory leak bug from TransformStream

* fix(executor): skip content persistence when stream consumer exits early

Previously, if the onStream consumer caught an internal error without
re-throwing, the block-executor would treat the shortened accumulator
as the complete response, persist a truncated string to memory via
appendToMemory, and set it as executionOutput.content.

Track whether the source ReadableStream actually closed (done=true) in
the pull handler. If onStream returns before the source drains, skip
content persistence and log a warning — the old tee()-based flow was
immune to this because the executor branch drained independently of
the client branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix lint

* fix(executor): early-return when no streamed content to make onFullContent symmetric

Previously, executionOutput.content was guarded by `if (fullContent)`
but `onFullContent` fired regardless. The agent-handler implementor
defensively bails on empty/whitespace content, but that's a callee
contract, not enforced at the call site — future implementors could
spuriously persist empty assistant turns to memory.

Hoist the `!fullContent` check to a single early return, so both the
output write and the callback share the same precondition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:23:36 -04:00
Waleed c32c1cb917 fix(security): patch copilot tool & multipart upload IDORs (#4304)
* fix(security): patch copilot tool & multipart upload IDORs

- multipart upload: bind upload session to (userId, workspaceId, key)
  via short-lived HMAC-signed token; require workspace write access at
  initiate; source key/uploadId/context from verified token (never
  client) at get-part-urls/complete/abort
- copilot knowledge-base tools: gate all 11 read/write/tag/connector
  ops with checkKnowledgeBaseAccess / checkKnowledgeBaseWriteAccess
- copilot user-table tools: add workspace-id check to get, get_schema,
  add/rename/delete/update_column to match existing op pattern
- copilot manage-credential: add full ownership/write-permission auth
  via getCredentialActorContext (previously had no auth)
- copilot restore-resource: verify workspace ownership and write
  permission for workflow, table, knowledgebase, file, and folder
  restores
- copilot folder rename/move: verify both folderId and parentId belong
  to the caller's workspace via new verifyFolderWorkspace helper
- copilot get-job-logs: verify schedule belongs to caller's workspace

* fix(security): address PR review — document IDOR, log count, token split

- knowledge-base delete_document/update_document: verify each document
  belongs to the claimed knowledgeBaseId via checkDocumentWriteAccess
  (was: trusted args.knowledgeBaseId without binding it to the document)
- multipart batch complete: log verifiedEntries.length instead of raw
  client-supplied data.uploads.length
- upload-token: reject tokens with !=2 dot-delimited segments

* fix(security): close folder workspace bypass when workspaceId is falsy
2026-04-27 11:05:22 -07:00
Vikhyath Mondreti 50e74f75ef fix(mothership): parallel subagent rendering, exec stream re-attach (#4299)
* fix(mothership): parallel subagent rendering

* fix rendering logic

* address comments

* cleanup dead code

* address mothership legacy key

* prevent id collision

* rollout stream edge case

* address bugbot comments"

* remove unused fallbacks

* fix execution stream attach, cleanup comments

* remove debug logs

* cleanup failed reconnect
2026-04-27 00:40:39 -07:00
Waleed 60652e621c fix(security): credential-set invite email check + shopify authorize XSS (#4302) 2026-04-26 20:52:42 -07:00
Waleed 8863f1132a feat(models): add gpt-5.5 models (#4300)
* feat(models): add gpt-5.5 models

* fix(models): address gpt-5.5 review feedback

* fix(models): align gpt-5.5 pro controls
2026-04-25 19:13:29 -07:00
Vikhyath Mondreti d93a6f57bc chore(guide): update contributing guide (#4296)
* chore(guide): update contributing guide

* fix md
2026-04-24 18:47:57 -07:00
Vikhyath Mondreti df581c3efb fix(mothership): queue supersede crash (#4297)
* fix(mothership): queue supersede crash

* add test

* abort observed marker
2026-04-24 18:31:46 -07:00
Vikhyath Mondreti f16d17ba49 improvement(mothership): do not silently re-route missing stream id (#4295) 2026-04-24 16:37:40 -07:00
Waleed e6fefc863c fix(table-block): resolve canonical tableId in filter/sort builders (#4294)
The visual filter/sort builders read the selected tableId from subBlock id
'tableId', but the Table block stores it under 'tableSelector' (basic) or
'manualTableId' (advanced) via canonicalParamId. The lookup always returned
null, so useTable was disabled and the column picker always showed
"no options available".

Adds useCanonicalSubBlockValue that resolves by canonicalParamId through
the canonical index, mirroring the pattern used by dropdown dependsOn.
2026-04-24 16:24:49 -07:00
Waleed 5fba724818 chore(bun): bump bun to 1.3.13 (#4291) 2026-04-24 15:59:10 -07:00
WaleedandClaude Opus 4.7 60b80ec172 improvement(tables): race-free row-count trigger + scoped tx timeouts (#4289)
* improvement(tables): race-free row-count trigger + scoped tx timeouts

* fix(tables): close upsert race + serialize replaceTableRows

Two concurrency bugs flagged by review:

1. `upsertRow` insert path: removing FOR UPDATE broke serialization between
   the initial existing-row SELECT and the INSERT. Two concurrent upserts
   on the same conflict target could both find no match, then both insert,
   producing a duplicate that bypasses the app-level unique check. Fixed
   by re-checking for the matching row *after* acquiring the per-table
   advisory lock; if a racing tx already inserted, switch to UPDATE.

2. `replaceTableRows`: under READ COMMITTED each tx's DELETE uses its own
   MVCC snapshot, so two concurrent replaces could each DELETE only the
   rows visible at their start, then both INSERT, leaving the table with
   the union of both row sets. Fixed by acquiring the per-table advisory
   lock at the start of the tx to serialize replaces against each other
   and against auto-position inserts.

Also updated a stale docstring on `upsertRow` that still referenced the
removed FOR UPDATE.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(tables): serialize explicit-position inserts with advisory lock

The `(table_id, position)` index is non-unique. Concurrent explicit-
position inserts at the same slot can both observe the slot empty, both
skip the shift, then each INSERT — producing duplicate `(table_id,
position)` rows.

Take the per-table advisory lock in the explicit-position branches of
`insertRow` and `batchInsertRows` (the auto-position branches already do
this). Updated the test that asserted the explicit path skipped the lock,
and added coverage for `batchInsertRows` with explicit positions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(tables): dedupe upsert UPDATE path + extract nextAutoPosition

Two pure cleanups on the round-1 changes:

1. Extract `nextAutoPosition(trx, tableId)` — the `SELECT coalesce(max(
   position), -1) + 1` pattern was repeated in three call sites
   (`insertRow` auto branch, `batchInsertRows` auto branch, `upsertRow`
   insert branch). One helper, same behavior.

2. Consolidate `upsertRow` update path. The initial-SELECT match and the
   post-lock re-select match previously had two literal duplicates of the
   same UPDATE + return block. Resolve `matchedRowId` first, then run one
   UPDATE branch. Lock is still only acquired when we don't find a match
   on the first pass.

No behavior change. 98/98 table unit tests unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 15:33:17 -07:00
Vikhyath Mondreti af4be770a1 improvement(mothership): treat error as terminal event (#4290) 2026-04-24 14:51:26 -07:00
WaleedandClaude Opus 4.7 f330fe22a2 refactor(ashby): align tools, block, and triggers with Ashby API (#4288)
* refactor(ashby): align tools, block, and triggers with Ashby API

Audit-driven refactor to destructure rich fields per Ashby's API docs,
centralize output shapes via shared mappers in tools/ashby/utils.ts,
and align webhook provider handler with trigger IDs via a shared
action map. Removes stale block outputs left over from prior flat
response shapes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): remove stale noteId output and reject ping events

- Remove stale `noteId` output descriptor from block (create_note
  now returns `id` at the top level via the shared note mapper).
- Explicitly reject `ping` events in the webhook matchEvent before
  falling back to the generic triggerId check, so webhook records
  missing triggerId cannot execute workflows on Ashby ping probes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): trim optional ID params in create/update tools

Optional ID params in create_application, change_application_stage,
and update_candidate were passed through to the request body without
.trim(), unlike their required ID siblings. Normalize to prevent
copy-paste whitespace errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): add subblock migration for removed filterCandidateId

Add SUBBLOCK_ID_MIGRATIONS entry so deployed workflows that previously
used the `filterCandidateId` subBlock on `list_applications` don't break
after the field was removed (Ashby's application.list doesn't filter by
candidateId). Also regenerate docs to sync noteId removal.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): final API alignment from parallel validation

- create_candidate: email is optional per Ashby docs (only name is
  required); tool, types, and block all made non-required.
- list_applications: guard NaN when createdAfter can't be parsed so we
  don't send a bad value to Ashby's API.
- webhook provider: replace createHmacVerifier with explicit
  fail-closed verifyAuth that 401s when secretToken, signature header,
  or signature match is missing (was previously fail-open on missing
  secret).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): preserve input.data path in webhook formatInput

Restore the explicit `data` key alongside the spread so deployed
workflows that reference `input.data.application.*`, `input.data.candidate.*`,
etc. keep working. The spread alone dropped those paths.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(ashby): drop legacy input.data key from webhook formatInput

Keep formatInput aligned with the advertised trigger outputs schema
(flat top-level entities) and drop the legacy input.data.* compat path.
Every field declared in each trigger's outputs is now populated 1:1 by
the data spread plus the explicit action key — no undeclared keys.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): trim remaining ID body params for parity

Add .trim() on sourceId (create_candidate), jobId (list_applications),
applicationId and interviewStageId (list_interviews) to match the
trim-on-IDs pattern used across the rest of the Ashby tools and guard
against copy-paste whitespace.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* update docs

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 13:29:26 -07:00
d 🔹 efc868263a fix(copilot): replace crypto.randomUUID() with generateId() per project rule (#4268)
AGENTS.md / CLAUDE.md forbid crypto.randomUUID() (non-secure contexts throw
TypeError in browsers). Four copilot server-side files still violated this
rule, left over after PR #3397 polyfilled the client.

Routes through request lifecycle, OAuth draft insertion, persisted message
normalization, and table-row generation now use generateId from @sim/utils/id,
which is a drop-in UUID v4 producer that falls back to crypto.getRandomValues
when randomUUID is unavailable.

Refs #3393.
2026-04-24 11:59:48 -07:00
Vikhyath Mondreti 56044776d5 improvement(mothership): stream retry state machine, progressive re-rendering (#4287)
* improvement(mothership): stream rety state machine, progressive re-rendering

* address comments
2026-04-24 11:56:53 -07:00
Theodore Li 04f1d015f3 fix(mothership): Use heartbeat mechanism for chat locks (#4286) 2026-04-24 14:36:50 -04:00
Waleed ccb5f1e690 fix(db): revert statement_timeout startup options breaking pooled connections (#4284) 2026-04-23 23:31:52 -07:00
Waleed 91ccbb9921 fix(agentphone): fix image (#4281) 2026-04-23 16:54:32 -07:00
Theodore Li dcbe7c69b0 feat(ui): Show subagent logs in bounded vertical view (#4280)
* feat(ui): render subagent actions in bounded box.

* Add gradients and scroll bar

* fix lint
2026-04-23 18:41:53 -04:00
Theodore Li c22ac38ab0 Set statement timeout of 90 seconds (#4276) 2026-04-23 18:27:15 -04:00
Waleed cdde8cbd66 feat(agentphone): add AgentPhone integration (#4278)
* feat(agentphone): add AgentPhone integration

* fix(agentphone): validate numeric inputs and metadata JSON

* chore(agentphone): remove dead from fallback in get_number_messages

* fix(agentphone): drop empty-string updates in update_contact

* fix(agentphone): scope limit/offset to list ops and revert stray IdentityCenter change

* lint
2026-04-23 15:20:19 -07:00
WaleedandClaude Opus 4.7 0ae19dab85 feat(files): default sort by updated and add updated sort option (#4279)
* feat(files): default sort by updated and add updated sort option

* feat(files): show Last Updated column

Matches the visible-column pattern already used on Knowledge and Tables
so users can see the value they're sorting by.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 15:02:07 -07:00
Waleed 3b11c814f8 fix(tables): account for letter-spacing and displayed content in column auto-resize (#4277) 2026-04-23 14:41:40 -07:00
Theodore Li b86ebb35fd fix(api): Pass archivedAt to list table response (#4275)
* fix(retention): switch data retention to be org-level

* fix lint

* cleanup mothership ran logs

* fix cleanup dispatcher

* fix ui flash for data retention settings

* fix lint

* remove raw sql string interprolation

* fix(api): return archivedAt for list tables route
2026-04-23 14:32:37 -04:00
Theodore Li 65972f2fa3 fix(retention): switch data retention to be org-level (#4270)
* fix(retention): switch data retention to be org-level

* fix lint

* cleanup mothership ran logs

* fix cleanup dispatcher

* fix ui flash for data retention settings

* fix lint

* remove raw sql string interprolation
2026-04-23 02:41:49 -04:00
5f0f0edd63 improvement(repo): separate realtime into separate app (#4262)
* improvement(repo): restructuring to make realtime image narrower scoped

* improvements

* chore(repo): rebase fixes and quality improvements for realtime split

Addresses merge-time issues and gaps from the realtime app split:
- Retarget stale vi.mock paths to @sim/workflow-persistence/subblocks
- Restore README branding, fix AGENTS.md script reference
- Restore TSDoc on workflow-persistence subblocks helpers
- Use toError() from @sim/utils/errors in save.ts
- Add vitest config + local mocks so @sim/audit tests run standalone
- Move socket.io-client to devDependencies in apps/realtime
- Add missing package COPY steps to docker/app.Dockerfile
- Add check:boundaries/check:realtime-prune scripts and wire into CI

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(security): consolidate crypto primitives into @sim/security

Move general-purpose crypto primitives out of apps/sim into the
@sim/security package so both apps/sim and apps/realtime can share them.

@sim/security exports (all pure, dependency-free):
  ./compare    safeCompare (constant-time HMAC-wrapped equality)
  ./encryption encrypt/decrypt (AES-256-GCM, iv:cipher:tag format)
  ./hash       sha256Hex
  ./tokens     generateSecureToken (base64url)

Migrate apps/sim call sites to use these + @sim/utils helpers:
  crypto.randomUUID()            -> generateId() from @sim/utils/id
  createHash('sha256').digest    -> sha256Hex
  timingSafeEqual on hashed hex  -> safeCompare
  new Promise(setTimeout)        -> sleep from @sim/utils/helpers

No behavior change: encryption format, digest output, and token
length are preserved exactly.

* refactor(copilot): use toError in remaining otel/finalize sites

Replace the last two `error instanceof Error ? error : new Error(String(error))`
patterns with toError from @sim/utils/errors. Completes the sweep of clean
candidates — no behavior change.

* refactor(security): consolidate HMAC-SHA256 primitives into @sim/security

Adds hmacSha256Hex and hmacSha256Base64 to @sim/security/hmac and migrates
15 webhook providers plus 5 other hot paths (deployment token signing,
outbound webhook requests, workspace notification delivery, notification
test route, Shopify OAuth callback) off bare `createHmac` calls. Secret
parameter accepts `string | Buffer` to cover base64-decoded Svix-style
secrets (Resend) and MS Teams' HMAC scheme. AWS SigV4 signing in S3 and
Textract tools intentionally retains direct `createHmac` usage — its
multi-step key derivation chain doesn't fit a generic helper.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(packages): post-audit test + packaging polish

- Add safeCompare unit tests (identity, length mismatch, hex-nibble diff).
- Add Buffer-secret cases to hmac tests to lock in Svix/MS-Teams contract.
- Declare `reactflow` as a peerDependency on @sim/workflow-types — only used for type imports.
- Add a barrel export to @sim/workflow-persistence for consumers that prefer package-level imports; subpath exports retained.
- Document the data-field invariant in load.ts for loop/parallel subflow patching.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(realtime): address PR review feedback

- Remove redundant SOCKET_PORT=3002 env from Dockerfile runner stage
  (env.PORT already defaults to 3002 via zod schema).
- Reorder PORT fallback so an explicitly-set SOCKET_PORT wins over
  the schema default for PORT; keeps SOCKET_PORT functional as an
  override instead of dead code.
- Add dedicated type-check CI step for @sim/realtime so TS errors
  surface pre-deploy (the Dockerfile runs source TS via Bun and has
  no implicit build-time type check).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(realtime): remove unused SOCKET_PORT env var

SOCKET_PORT has lived in the socket server since the June 2025 refactor
but was never actually set in any deploy config — docker-compose.prod,
helm values/templates, .env.example, and docs all use PORT or the 3002
default exclusively. No self-hoster was ever pointed at SOCKET_PORT, so
removing it is safe.

Simplifies realtime port resolution to `env.PORT` (zod-validated with a
3002 default) and drops the orphaned sim-side schema entry.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Waleed Latif <walif6@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 23:06:16 -07:00
Waleed bed5e95742 fix(selectors): enable search on all picker and selector subBlocks (#4269) 2026-04-22 20:40:59 -07:00
Theodore Li f7ab39984c feat(ui): add thinking ui to mothership (#4254)
* feat(ui): Add thinking ui

* fix tests

* Remove duplicate helper for block timing

* fix lint

* fix endedAt timestamp bug

* fix stuck subagent thinking
2026-04-22 19:52:56 -04:00
Theodore Li 8ce56fe1f2 fix(auth): add api key auth via sha256 hash lookup (#4266)
* fix(auth): add api key auth via sha256 hash lookup

* Remove promise all logic

* Restore feature flag

* fix feature flag

* Combine auth and hash gate
2026-04-22 18:30:37 -04:00
Vikhyath Mondreti 8c9ddefc53 fix(otel): chat root OTel span on all early-return paths (#4265) 2026-04-22 13:54:47 -07:00
Theodore Li d927d8bdff fix(db): raise db pool size (#4263)
* fix(db): raise db pool size

* Raise socket connections

* bump up connection size even more
2026-04-22 14:25:13 -04:00
Siddharth Ganesan 0aeab026a8 feat(observability): add mothership tracing (#4253) 2026-04-22 09:06:01 -07:00