mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
b6679a98809f792a85efa1a6799fcb2056cd63fc
4646
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b6679a9880 |
feat(google-slides): complete API surface for branded slide generation (#4678)
* feat(google-slides): complete API surface for branded slide generation * fix(google-slides): address PR review — explicit videoId mapping, fast base64 export, remove dead utility * fix(google-slides): declare z-order operation output in block outputs map |
||
|
|
7e678552d6 |
improvement(elevenlabs): wire stability and similarity_boost end-to-end (#4679)
* improvement(elevenlabs): wire stability and similarity_boost end-to-end * fix(elevenlabs): guard NaN in voice settings and always send both knobs together |
||
|
|
a1b2130256 |
improvement(knowledge): batch trigger dispatch, prune redundant DB roundtrips (#4680)
* improvement(knowledge): batch trigger dispatch, prune redundant DB roundtrips Connector sync was dispatching Trigger.dev document-processing jobs one HTTP roundtrip at a time. processDocumentsWithQueue now uses tasks.batchTrigger when Trigger.dev is available, collapsing N roundtrips to ceil(N/1000). Idempotency keys protect against duplicate runs on retry. Also trims DB roundtrips inside the sync loop: - Per-batch isConnectorDeleted + isKnowledgeBaseDeleted collapsed into a single checkSyncLiveness JOIN (one SELECT instead of two per batch). - Dropped redundant pre-upload isKnowledgeBaseDeleted checks from addDocument/updateDocument: the batch-boundary liveness check already catches pre-batch deletions and the in-tx FOR UPDATE is authoritative for races during the batch. - Removed dead processDocumentsWithTrigger helper (never called). * refactor(knowledge): split dispatch helpers, drop dead trigger branch - Use the canonical DocumentProcessingPayload from the task module instead of the duplicate DocumentJobData interface in service.ts - Pass typeof processDocumentTask as a generic to tasks.batchTrigger so the payload shape is type-checked against the task definition - Inline TRIGGER_BATCH_SIZE provenance (Trigger.dev SDK 4.3.1+ doc'd cap, we're on 4.4.3) - Split direct vs trigger dispatch into dispatchInProcess and dispatchViaBatchTrigger; collapse the all-failed throw into a single check on the combined dispatched counter - Remove dispatchDocumentProcessingJob — its trigger branch is no longer reachable now that batchTrigger handles the trigger path, and the direct branch is inlined * improvement(knowledge): log Trigger.dev batchIds for audit trail tasks.batchTrigger returns a batchId per call. Collecting and logging them after dispatch makes it possible to look up or cancel batches in the Trigger.dev dashboard when investigating stuck or missing documents. * improvement(knowledge): thread requestId through direct dispatch logs Symmetry polish: dispatchInProcess now includes [requestId] in its error log so direct-mode failures are correlatable the same way trigger-mode failures already are. * improvement(knowledge): trim verbose comments Tightens TSDoc on processDocumentsWithQueue, TRIGGER_BATCH_SIZE, checkSyncLiveness, and the idempotency-key inline comment. |
||
|
|
c3815509b2 |
fix(landing-nav): scroll to top on route change in shared shells (#4676)
* fix(landing-nav): scroll to top on route change in shared shells * fix(landing-nav): hoist popstate flag to module scope and skip on hash anchors * fix(landing-nav): use popstate timestamp window so flag self-expires * fix(landing-nav): use -Infinity sentinel and consume popstate timestamp on use * fix(landing-nav): skip scroll on initial mount so reload restoration wins * fix(landing-nav): gate initial-mount skip on document.readyState * refactor(landing-nav): simplify scroll-to-top to conventional pattern |
||
|
|
af8025c411 |
fix(table): dispatcher cold-start, live run counter, smooth typewriter (#4675)
* fix(table): cut dispatcher cold-start by lazy-loading heavy import chains The trigger.dev table-run-dispatcher spent ~6s in module init before its first batchTriggerAndWait — it imports lib/table/service for getTableById, which eagerly imported lib/table/trigger → @/lib/webhooks/processor → webhook-execution + executor, dragging the entire workflow-execution stack into the dispatcher container even though it never fires a trigger. - trigger.ts lazy-imports the webhook processor + polling utils inside fireTableTrigger (the only consumer), so importing service no longer pulls the executor. - buildEnqueueItems only imports the cell job (for the inline `runner`) on the database backend; the trigger.dev backend triggers by task id and ignores runner. * fix(table): run counter + gutter Stop update instantly on Run The "X running" badge, per-row gutter Stop button, and runningByRowId map stayed at zero after clicking Run until a manual refetch. useRunColumn optimistically stamped cells pending in the rows cache but never bumped the activeDispatches counter — so when the dispatcher's real pending SSE arrived, applyCell saw the cell was already in-flight (wasInFlight === isInFlight) and skipped the counter delta. The optimistic stamp ate the transition. - onMutate now bumps runningCellCount / runningByRowId by the cells it stamps, snapshotting prior run-state for rollback on error. - onSuccess seeds the dispatch into the overlay list from the response instead of invalidating activeDispatches (a refetch would reset the optimistic counter to the server's still-zero count before the dispatcher stamps). * fix(table): drive cell typewriter with rAF so concurrent reveals stay smooth The character-by-character reveal used a per-cell setInterval. When many cells reveal at once (a Run-all completing in waves), the independent interval callbacks fire at uncoordinated times and each forces its own render + layout/paint — O(cells) reflows over an un-virtualized grid, so it degrades as more cells fill. Switch to requestAnimationFrame: all cells' callbacks run before one paint, so React batches them into a single render + paint per frame regardless of cell count. Reveal length is derived from elapsed time, so a dropped frame catches up instead of slowing the animation. * fix(table): roll back optimistic run counter when no dispatch is created useRunColumn.onSuccess returned early on a null dispatchId (no matching groups / eligible rows) without undoing the onMutate counter bump — and no SSE would arrive to correct it, leaving the counter permanently inflated. Restore the pre-mutation run-state on that path, mirroring onError. * chore(table): tighten inline comments on dispatcher cold-start fixes |
||
|
|
46db40620f |
feat(mcp): OAuth 2.1 + PKCE for outbound MCP servers (#4441)
* feat(mcp): OAuth 2.1 support for outbound MCP servers
* fix(mcp): tighten OAuth refresh race and session-error detection
Re-load the OAuth row inside withMcpOauthRefreshLock so concurrent
callers observe predecessor-written tokens instead of a stale snapshot
loaded before lock acquisition. Without this, the second caller's
provider held a rotated-out refresh token and the SDK tripped
invalid_grant, forcing reauthorization.
Switch isSessionError to match the SDK's typed StreamableHTTPError
(code 404/400) instead of substring-checking arbitrary error messages,
removing false positives on URLs that happen to contain those digits.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* refactor(mcp): tighten OAuth callback contract and registration metadata
- Validate callback query params via mcpOauthCallbackContract instead of
raw searchParams.get, matching the rest of the MCP route surface.
- Drop non-RFC-7591 application_type field from dynamic client registration
to avoid rejection by strict authorization servers.
- Collapse the pre-lock OAuth row load in createClient — the row is now
loaded exclusively inside withMcpOauthRefreshLock, removing a redundant
query and a stale-snapshot path.
* fix(mcp): narrow workspaceId before async closure in OAuth createClient
* fix(mcp): return authType from create-server endpoint
The POST /api/mcp/servers handler omitted authType from the success
response, so useCreateMcpServer always saw data.data.authType as
undefined and never triggered the OAuth popup after creating an
OAuth-protected server. Thread authType through performCreateMcpServer
into the response so the client can decide whether to auto-start OAuth.
* fix(mcp): mirror server null normalization in optimistic oauthClientId update
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(mcp): revert optimistic oauthClientId to undefined to match McpServer type
The response contract preprocesses null → undefined, so McpServer.oauthClientId
is string | undefined. Using null broke type checking.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(mcp): tighten OAuth probe signal and clear stale popup interval
- probe: only classify as OAuth on resource_metadata or scope params.
Bare `Bearer error="invalid_token"` is generic and used by API-key servers,
so it must not auto-flip the auth type to OAuth.
- popup hook: clear any existing close-watcher interval before overwriting
when startOauthForServer is invoked twice for the same serverId.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(mcp): normalize empty-string oauthClientId at route boundary
Orchestration already converts falsy → null via `|| null` (server-lifecycle.ts),
so the DB was never receiving an empty string. Tightening the route layer to
match the same convention keeps the boundary contract consistent and avoids
relying on downstream normalization.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(canvas): expand MCP tool params into per-row labels on block tile
The MCP Tool block on the workflow canvas previously crammed every selected-
tool parameter into a stringified blob under the `Tool` row. Now, when a tool
is selected, the tile reads the cached `_toolSchema` and emits one labeled
SubBlockRow per parameter (matching the Exa block's per-param layout). Labels
reuse `formatParameterLabel` for parity with the editor panel; values pass
through the existing `getDisplayValue` so booleans/numbers/arrays render
identically to other blocks. Deterministic tile height counts expanded rows
so the tile sizes correctly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(logs): show MCP icon and strip prefix in trace tool spans
Tool spans for MCP calls were rendering the raw id (e.g.
`mcp-f908f259-planetscale_list_organizations`) with the default blank-
square icon. Now they read just the tool name and render the MCP block's
icon and bgColor, matching how workflow-execute tools render.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(logs): lift near-black trace icon backgrounds for dark-mode contrast
Block bgColors below a small luminance threshold (e.g. the MCP block's
#181C1E) rendered nearly invisible against the dark-mode surface
(--bg: #1b1b1b). Adds a tiny adjustBgForContrast helper that floors each
RGB channel at 0x33 only when luminance is below 30,000, leaving every
branded color above that band untouched. Applied to both the trace tree
row and the detail pane.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(logs): fall back to neutral gray for near-black trace icon bgs
#333333 was still too close to the dark-mode surface to read. For bgs
below the luminance threshold (e.g. the MCP block's #181C1E) we now fall
back to DEFAULT_BLOCK_COLOR (#6b7280) — the same neutral the renderer
uses for blocks with no distinct identity. Clearly visible in both
themes; brighter brand colors still pass through.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(db): drop 0209_mcp_oauth migration ahead of staging merge
Staging shipped 0209_smiling_fixer; the MCP OAuth migration will be
regenerated on top of staging as 0210.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(db): regenerate MCP OAuth migration as 0210
Re-runs drizzle-kit generate on top of staging's 0209_smiling_fixer.
Same schema (mcp_server_oauth table + mcp_servers.auth_type / oauth_*
columns) as the dropped 0209_mcp_oauth.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(audit): bump route baseline 748 → 749 after staging merge
The post-merge route count is 749 (this branch's OAuth start/callback
plus staging's new route). I had set the baseline to 748 in the merge
conflict resolution — bumping to match reality so the strict audit
passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: remove source-command skill files committed by accident
These were untracked-then-accidentally-staged in
|
||
|
|
d9dd7a3e55 |
fix(cors): re-enable credentials on chat/form embed CORS policy (#4673)
* fix(cors): re-enable credentials on embed CORS policy Chat and form embeds authenticate via the chat_auth_<id> / form auth cookie set by setDeploymentAuthCookie. The previous PR set Access-Control-Allow-Credentials: false on these routes, which made the browser drop the auth cookie and produce 401s on subsequent embed calls after login. Restore credentials: true (matching pre-consolidation behavior) while keeping reflected origin and Vary: Origin. The wildcard fallback when Origin is absent now also drops credentials to stay CORS-spec-compliant. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore(cors): trim verbose comments in proxy Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore(cors): restore concise TSDoc on proxy CORS helpers Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
f0311a6f5e |
feat(table): chunked dispatcher + workflow cascade (#4672)
* feat(table): chunked dispatcher for workflow-column runs
Replaces the all-rows-at-once runWorkflowColumn with a row-window dispatcher
backed by a new table_run_dispatches row. Each user click inserts a dispatch
row and triggers a trigger.dev task that crawls the table 20 rows at a time,
re-enqueueing itself between windows. The HTTP/Mothership entrypoints return
{ dispatchId } immediately instead of holding the request open for minutes
on multi-thousand-row dispatches.
- Per-row cancel stamps cancelledAt; the dispatcher skips cells whose
cancelledAt > dispatch.requestedAt so a mid-cascade cancel sticks even
under isManualRun.
- Table-wide cancel marks active dispatches cancelled atomically so the
dispatcher bails on its next iteration.
- New 'dispatch' SSE event variant plumbed; client ignores for v1.
* fix(table): eager bulk clear on column run so cells flip immediately
Run-column with run-mode 'all' wasn't visually flipping rows that already
had data — the cell renderer's "value wins" branch kept showing the prior
output behind the queued/running state. The dispatcher only cleared one
window of rows at a time, so most of the column stayed stale until the
cursor walked to it.
Now:
- Dispatcher's `pending → dispatching` transition runs a single SQL UPDATE
that wipes targeted `data` output columns and `executions[gid]` across
every targeted row (mode-aware: 'incomplete' skips fully-filled rows).
- Per-window clear in `dispatcherStep` is gone — rows are pre-cleared,
the loop only filters cancel tombstones / unmet deps and enqueues.
- Optimistic patch in `useRunColumn` mirrors the bulk clear by nulling
output values in the cached row, so the UI flips queued/running
instantly without waiting for the SSE catch-up.
* fix(table): bulk clear honors in-flight execs under mode: 'incomplete'
The eager bulk clear for mode: 'incomplete' only skipped rows that were
already fully filled, so two overlapping dispatches could race — dispatch B
would nuke executions[gid] on a row dispatch A had just stamped 'queued',
flickering the cell and potentially confusing the worker.
Skip any row whose targeted group is currently queued/running/pending — an
'incomplete' run shouldn't touch what another dispatch is actively working
on. The per-walk 'in-flight' eligibility skip already handles rows that
flip in-flight between the clear and the cursor reaching them.
* refactor(table): dispatcher uses batchTriggerAndWait + tag-based cancel
Switch the per-window cell fan-out from fire-and-forget tasks.trigger to
tasks.batchTriggerAndWait. The dispatcher is now a single long-lived
trigger.dev task that loops dispatcherStep until the table is exhausted;
trigger.dev CRIU-checkpoints the parent during each wait so we don't pay
compute while cells execute. Queue depth is bounded at WINDOW_SIZE per
dispatch — no more flooding trigger.dev with a million queued runs.
- dispatcher.ts builds payloads via the new shared buildPendingRuns helper
and calls tasks.batchTriggerAndWait directly. Pre-stamps each cell to
`queued` (jobId=null) so the UI flips instantly.
- table-run-dispatcher.ts is now a plain while-true loop. No
RUN_BUDGET_MS, no self-re-enqueue, no cold-start tax per window.
Cancel:
- New cancelCellRunsByTags(tags) paginates runs.list + runs.cancel(id).
- cancelWorkflowGroupRuns fires the tag-sweep alongside the per-jobId
queue.cancelJob path (preserved for auto-fire cells that have real
jobIds from single tasks.trigger calls).
- Trigger.dev acks the cancel → batchTriggerAndWait resumes → dispatcher
observes the dispatch-row cancel flag → exits.
Side fixes:
- getAsyncBackendType returns 'trigger-dev' whenever taskContext.isInsideTask
is true, regardless of TRIGGER_DEV_ENABLED env. The preview/dev-sim
worker silently routing cell jobs to DatabaseJobQueue (no poller) is
fixed without any env config change.
- runWorkflowColumn skips the dispatcher entirely when trigger.dev is
disabled, running cells inline via DatabaseJobQueue.runInline. HTTP
response returns dispatchId: null in that mode.
- runColumnContract response schema updated to dispatchId.nullable().
* fix(table): show Stop button on optimistic-pending row cells
isExecInFlight required a jobId for `pending` status, gating it as "real
backend pending" vs "optimistic flag only." The row-gutter Stop button
keyed on this — so a freshly clicked Play sat as `pending` (no jobId) and
the user couldn't cancel it until the server-side `queued` stamp arrived
via SSE. With the dispatcher pre-batch stamping cells as `queued` (not
`pending`) and no per-cell jobIds under batchTriggerAndWait, the gap was
worse.
Drop the jobId requirement. `pending` now counts as in-flight everywhere.
Cancel writes `cancelled` to the cell exec authoritatively whether or not
a real trigger.dev run exists yet — cancelling an optimistic cell means
"don't run this," which is correct.
Also collapse isOptimisticInFlight into isExecInFlight since the two
helpers are now identical.
* refactor(table): loop-in-cell cascade + dispatcher-everywhere routing
Two coupled changes:
1. Cell-task runs the row's full cascade in-process. executeWorkflowGroupCellJob
acquires a Redis lock per (tableId, rowId) with heartbeat (10s/30s TTL),
then loops through eligible workflow groups for the row. One cell-task =
one row's full cascade, not N. Resume worker holds the same lock and
continues the cascade after a HITL resume. Shared withCascadeLock helper
in lib/table/cascade-lock.ts.
2. Every cell-enqueue goes through the dispatcher. The implicit
scheduleRunsForRows reactor in service.ts is removed — 8 callsites
(insertRow, batchInsertRows, upsertRow, updateRowsByFilter,
batchUpdateRows, addWorkflowGroup, updateWorkflowGroup) now fire
runWorkflowColumn with mode: 'incomplete', isManualRun: false. HTTP
routes that call updateRow directly also fire runWorkflowColumn
afterwards. scheduleRunsForTable / scheduleRunsForRowIds deleted;
scheduleRunsForRows demoted to private (only the TRIGGER_DEV_ENABLED=false
fallback uses it). skipScheduler flag dropped from UpdateRowData /
BatchUpdateByIdData — no longer meaningful since there's nothing implicit
to suppress.
Plumbed isManualRun through the dispatch row (new is_manual_run column,
default true) so auto-fire callers honor autoRun: false and don't re-run
completed cells.
Stamp 'pending' (not 'queued', executionId: null) before
batchTriggerAndWait — cell-task writes its own 'queued' on lock acquire.
Small UI polish: row gutter Play button spacing, "Delete workflow" →
"Delete column" label, optimistic-pending cells now show Stop button
(isExecInFlight no longer requires jobId).
* fix(table): SQL cancellation guard allows worker to claim a null-execId cell
The dispatcher's pre-batch `pending` stamp leaves executionId unset so any
cell-task that wins the cascade lock can claim the cell. The cancellation-
guard SQL clause was rejecting these claims because it tested
`executions->gid IS NULL` (whole exec missing) but the pre-stamp leaves
the exec present with executionId=null.
Add a third carve-out: `executions->gid->>'executionId' IS NULL`. Now the
guard reads "write allowed if no exec exists, OR no executionId is set
yet, OR the executionId matches ours."
Symptom: every cell-task's first markWorkflowGroupPickedUp call would log
"SQL guard saw cancelled" and skip, leaving cells stuck at the dispatcher's
pending stamp.
* fix(table): dispatcher cursor starts at -1 so position 0 is included
The dispatcher's row-window SELECT is `position > cursor` for exclusive
lower-bound semantics. With cursor initialized to 0, position-0 rows were
never picked up — every dispatch silently skipped the table's first row.
Start cursor at -1 instead. First window's filter `position > -1` matches
position 0; subsequent iterations advance to `lastPosition` which then
correctly excludes already-processed rows.
* refactor(table): align optimistic UI with new dispatcher; sticky cancel via 'new' mode
Fix 0: new `DispatchMode = 'new'` for auto-fire callsites. Eligibility skips
rows with any prior `executions[gid]` entry — cancelled / errored / completed
cells stay sticky until a manual run. Dispatcher's windowed SELECT pushes
`NOT jsonb_exists_any(...)` to SQL so CSV imports into mostly-attempted
tables don't pay a per-window load+JS-filter. `batchInsertRows` drops its
`rowIds` payload (keeps dispatch scope tiny on big imports).
Fix A/B/D: client optimistic patches now mirror the backend's actual
invariants. `useCreateTableRow.onSuccess` stamps eligible groups via
`optimisticallyScheduleNewlyEligibleGroups` so newly-inserted rows show
`Queued` instantly. `useCancelTableRuns.onMutate` distinguishes optimistic-
only pending (`executionId == null` — strip silently) from real worker
claims (stamp cancelled; SSE will reconcile). Drop `onSettled` invalidation
on `useUpdateTableRow` / `useBatchUpdateTableRows` to kill the
delete-cell flicker.
Fix C: active-dispatches overlay. New `listActiveDispatches` helper,
contract, and `GET /api/table/[tableId]/dispatches` route. `kind:'dispatch'`
SSE events carry scope+cursor+mode on every transition. New
`useActiveDispatches` hook + `resolveCellExec` synthesize a virtual
`pending` exec for cells in an active dispatch's scope ahead of cursor —
queued indicators now survive page refresh during long Run-all dispatches.
`cancelWorkflowGroupRuns` emits `kind:'dispatch',status:'cancelled'`
events so the overlay clears without a refetch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(table): unify trigger.dev and inline dispatcher paths
`runWorkflowColumn` now always inserts a `table_run_dispatches` row and
drives the dispatcher state machine. The trigger.dev / in-process branch
narrows to a single line: trigger.dev fires `tableRunDispatcherTask` (which
calls the new `runDispatcherToCompletion`), the inline path calls the same
helper fire-and-forget. Deletes `scheduleRunsForRows` and
`stampQueuedOrCancel` — the inline-fallback no longer duplicates window
walking, SSE emission, or cancel.
The dispatcher's window-execute call goes through `JobQueueBackend`:
- New `batchEnqueueAndWait` interface method.
- Trigger.dev impl wraps `tasks.batchTriggerAndWait` behind a
`taskContext.isInsideTask` guard (clear error if called from outside a
task).
- Database impl skips `async_jobs` entirely — `Promise.all` over
`options.runner(payload, signal)` per item, with per-cell AbortControllers
tracked by `cancelKey` for cancel.
`cancelInlineRun` moves to the interface as `cancelByKey` so
`cancelWorkflowGroupRuns` no longer reaches into the database backend.
Fix `mode: 'new'` SQL filter:
- `${array}::text[]` interpolated as a tuple-cast which Postgres rejected
("cannot cast type record to text[]") and every inline dispatch silently
failed. Switched to `ARRAY[${sql.join(...)}]::text[]`.
- Predicate was `jsonb_exists_any` ("any one targeted group present"),
which excluded rows that needed at least one group re-run after a
downstream output was deleted. Switched to `jsonb_exists_all` — per-group
JS eligibility handles the rest.
Cascade-loop workflowId bug: `runRowCascadeLoop` was not threading the new
group's `workflowId` when advancing across groups. The cell-task ran the
previous group's workflow against the next group's cell, terminating
`completed` with empty `accumulatedData`. Fixed by tracking
`currentWorkflowId` alongside `currentGroupId` / `currentExecutionId`.
Client optimistic-patch tightening:
- `useRunColumn.onMutate` mirrors server eligibility — skip cells with
unmet deps so unmet rows don't flash Queued and get stuck (no SSE will
arrive for cells the server skipped).
- `resolveCellExec` overlay synthesizes a virtual `pending` only when
`areGroupDepsSatisfied` is true. Rows with unmet deps render Waiting,
matching the dispatcher's actual behavior.
Cleanup from /simplify pass:
- Use `generateShortId(20)` instead of
`generateId().replace(/-/g, '').slice(0, 20)`.
- Inline `batchEnqueueAndWait` no longer allocates synthetic ids
(returned `string[]` is unused).
- Flattened the per-cell `tracked` array — only push entries that
registered controllers, drop the null placeholders.
- Extracted `runDispatcherToCompletion` to share the loop between the
trigger.dev wrapper and the in-process path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(table): backend running counter, dep-aware retrigger, sidebar polish
Counter (Fix 1): top-right "X running" + per-row badge are now
backend-bootstrapped via a count on `user_table_rows.executions ->> 'status'
= 'running'` returned alongside active dispatches. SSE `kind: 'cell'` events
compute a delta from `prev → next` status to keep the cache live; cell
events for rows outside the loaded page slice trigger a run-state refetch.
On `pruned` we invalidate the cache. Counts only worker-claimed `running`
cells — optimistic queued/pending no longer inflate the badge, and rows
outside the loaded page slice are counted too.
Sidebar (Fix 2 + 3a): `Run after` no longer ticks every column by default
for new groups (empty list). Save is disabled with an inline error when
auto-run is on with zero deps. `edit-group` mode anchors the left-of-current
filter to the group's leftmost column, so a workflow can only depend on
columns to its left.
Reorder scrub (Fix 3b): `updateTableMetadata` walks the schema's workflow
groups when `columnOrder` is in the patch and drops any dep whose new
position lands at or after the group's leftmost column (uses the existing
`stripGroupDeps` helper). Metadata + schema updates land atomically.
Server returns ordered columns (Fix 3b cont'd): `getTableById` /
`listTables` now sort `schema.columns` by `metadata.columnOrder` before
returning, via a new `applyColumnOrderToSchema` helper. Every consumer
(grid, sidebar, copilot, mothership) gets one ordered list — the sidebar's
leftmost-group-column anchor now points at the right index.
Dep-aware retrigger (Fix 4): editing a value that a downstream workflow
depends on now re-runs that workflow.
- `deriveExecClearsForDataPatch` returns
`{ executionsPatch, inFlightDownstreamGroups }`. Walks
`schema.workflowGroups[].dependencies.columns` for every column in the
patch, clears terminal-state downstream entries, and reports in-flight
entries.
- `updateRow` calls `cancelWorkflowGroupRuns` + `runWorkflowColumn`
(`mode: 'incomplete' + isManualRun: true`) for in-flight downstream
groups, then always fires `runWorkflowColumn({ mode: 'new' })` for the
cleared groups. Skips both when `executionsPatch` is provided by the
caller — those are cell-task / cancel writes that would otherwise spawn
a recursive flood of dispatches per partial-write.
- `cancelWorkflowGroupRuns(tableId, rowId, { groupIds? })` accepts a
per-group filter so the cancel only touches the affected groups, not
every in-flight cell on the row.
- `pickNextEligibleGroupForRow` now treats a dispatcher pre-stamp
(`pending` + `executionId: null`) as claimable — the cascade-loop is the
real owner. Without this, the dispatcher's pre-stamp of downstream
groups made the cascade-loop see them as "in-flight" and skip them,
stranding `pending` cells forever.
- `optimisticallyScheduleNewlyEligibleGroups` extends the cache patch to
flip dep-touched groups to `pending` regardless of their current status,
matching the server's cancel-then-rerun behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(table): paused workflow cells route through executeResumeJob; render Pending + viewable
Three connected issues with workflows that pause mid-cell (e.g. wait blocks):
1. `/api/resume/poll` (the time-pause auto-resumer) called
`PauseResumeManager.startResumeExecution` directly, bypassing
`executeResumeJob` from `background/resume-execution.ts`. The wrapper is
where the cell-context restoration + cascade-loop continuation lives —
without it, the resumed workflow ran to completion but never wrote the
terminal state back to the table cell. Cell stays `pending` forever
even though the underlying execution finished.
Fix: dynamically import `executeResumeJob` and use it for the
`'starting'` branch. Same primitive the trigger.dev `resumeExecutionTask`
wraps — calling it directly handles both trigger.dev-disabled local dev
and trigger.dev-enabled prod identically.
2. The cell renderer mapped `status: 'pending'` to `kind: 'queued'` (gray
"Queued" badge) regardless of whether the run had started. A HITL-paused
run has `status: 'pending'` + `jobId` prefixed `paused-` + a real
`executionId` — semantically very different from "queued, hasn't run."
Now renders as `pending-upstream` (the existing Pending pill) for
paused-jobId rows.
3. Right-click "View execution" was disabled for `pending` cells (gated to
`completed | error | running`), so users couldn't open the trace for a
paused execution. Paused runs have a viewable trace (the executionId is
real and the log row exists). Both the per-row context menu and the
action-bar derivation now recognize `pending` + `paused-` jobId as a
started run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(table): typewriter reveal for SSE-driven workflow cell values
Workflow-output cells now reveal their text character-by-character when an
SSE update lands, while page reloads and virtualization remounts still paint
the value instantly. A first-render guard inside the new useTypewriter hook
distinguishes hydration from live updates with no plumbing through the cell
tree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(table): address bugbot/greptile review feedback
Two P1 issues + one cleanup from the bot reviewers:
1. **Double-dispatch + completed-output wipe.** Both PATCH row routes
(`app/api/table/[tableId]/rows/[rowId]` and
`app/api/v1/tables/[tableId]/rows/[rowId]`) were firing a second
`runWorkflowColumn({ mode: 'incomplete' })` after `updateRow` returns.
`updateRow` already fires `mode: 'new'` internally for user edits, so
the second call created a concurrent dispatch. Worse, the
`mode: 'incomplete'` path's `bulkClearWorkflowGroupCells` wipes ALL
targeted output columns on any row where any one column is empty —
meaning sibling-group completed outputs could be erased. Removed both
route-level calls; auto-dispatch lives entirely in `updateRow`.
2. **`runWorkflowColumn` log-spamming on plain tables.**
`if (targetGroups.length === 0) throw new Error(...)` fired on every
row insert/update for tables without any workflow groups (the
majority). Every caller wraps with `.catch(logger.error)`, so each
PATCH produced an error-level log. Return `{ dispatchId: null }`
silently — manual `runWorkflowColumn` callers pass `groupIds`
explicitly so they can't reach this branch.
3. **`isManualRun` plumbed through dispatch SSE events.** Late-arriving
`kind: 'dispatch'` events for dispatches not in the initial fetch
were hardcoding `isManualRun: false`. Added the field to the event
shape, emit it from `dispatcherStep` (pending → complete, dispatching
transitions) and `markActiveDispatchesCancelled`, and consume it in
the SSE handler with a sensible fallback for legacy emits.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(table): row executions sidecar + left-to-right dep retrigger + cancel counter refresh
Split per-row workflow-group execution state out of the user_table_rows.executions
JSONB column into a new table_row_executions sidecar keyed by (row_id, group_id).
Dispatcher filters, "X running" counter, bulk clears, and the cancellation guard
all hit indexed columns instead of walking JSONB. Wire shape unchanged — server
merges sidecar rows back into row.executions on the way out.
Also:
- deriveExecClearsForDataPatch now walks workflowGroups left-to-right with a
propagating dirtied-column set so transitive dep chains (edit col A → group 1
re-runs → group 2 depends on group 1's output → group 2 re-runs) collapse to
a single forward pass.
- useCancelTableRuns.onSettled invalidates the activeDispatches query so the
top-right counter and row gutter Stop button refetch from the server after
any Stop (per-cell, row, or table-wide). countRunningCells is the source of
truth; client no longer needs duplicate state.
Three migrations on this branch (0209 + 0210 + new sidecar) collapsed into one
since the feature is unreleased.
* fix(table): address remaining cursor/greptile review feedback
- Mothership update_row no longer double-dispatches. updateRow already fires
the auto-cascade internally; the second `mode: 'incomplete'` call here
raced with it and could bulk-clear sibling-group outputs.
- SSE dispatch events no longer dropped when the activeDispatches cache is
cold. Seed an empty TableRunState if the initial fetch hasn't landed yet
so the queued overlay doesn't lose the first dispatch event.
- batchUpdateRows now runs cancel+rerun for per-row in-flight downstream
groups, mirroring updateRow. Without this, dep edits in a batch left
running workflows reading stale upstream values.
* fix(table): cancel prior runs, scope batch insert dispatch, recover orphan pre-stamps
Addresses cursor + greptile review feedback on table dispatcher edge cases:
- Manual table-wide Run-all / Run-column now cancels prior active dispatches
AND in-flight cell workers before bulk-clearing. Without this, mode:'all'
deleted running sidecar rows out from under their workers (which kept
writing into the wiped state) and a second Run-all could enqueue overlapping
cells racing on the same rows. Row-scoped manual calls (dep-edit cascade)
are excluded — those already cancel their own scope.
- batchInsertRowsWithTx now scopes its auto-dispatch to the newly-inserted
row ids. Without this, after the sidecar migration the NOT EXISTS filter
matches every existing row (zero sidecar entries), so a CSV import would
walk the entire table dispatching workflow runs on every pre-existing row.
- classifyEligibility carve-out: pending + executionId=null is an orphan
pre-stamp (cascade-lock contention, batchEnqueueAndWait failure, etc.),
treated as claimable so future dispatchers can re-stamp instead of skipping
it as 'in-flight' forever. Matches pickNextEligibleGroupForRow's logic.
- On batchEnqueueAndWait failure, dispatcherStep now sweeps the orphan
pre-stamps it wrote for the failed batch so the cells don't render Queued
forever; the next user action picks them up cleanly.
* fix(table): row-scoped Refresh cancels in-flight; counter includes queued/pending
- runWorkflowColumn now cancels prior in-flight cells for row-scoped manual
runs too (context-menu Refresh on a row subset, action-bar Refresh on
selected rows). Previously only the table-wide path cancelled, so a
row-scoped Refresh would bulk-clear running sidecar rows without aborting
workers. Per-row cancel skips markActiveDispatchesCancelled so unrelated
dispatches keep running.
- countRunningCells now counts all in-flight statuses (queued / running /
pending) instead of just running. The row gutter Run/Stop button reads
this map — with the old behavior, clicking Play during the queued window
would re-enqueue an already-queued cell. SSE applyCell handler updated
to use isExecInFlight so client deltas track the same semantics.
* fix(table): per-row Stop tombstones ahead-of-cursor rows during Run-all
Per-row Stop only cancelled sidecar rows already in flight. A row the
dispatcher hadn't reached yet had no exec record, so Stop was a no-op there
— the dispatcher would later walk to it, classify the group eligible, and
re-fire workflows the user thought they stopped.
cancelWorkflowGroupRuns now, for a per-row cancel, checks active dispatches
whose scope covers the row and writes `cancelled` tombstones (cancelledAt =
now) for the at-risk groups that don't already have a sidecar entry. The
dispatcher's existing `cancelledAt > dispatch.requestedAt` filter then skips
them when the cursor arrives. onConflictDoNothing guards against clobbering
a concurrently-written entry; the active-dispatch check avoids stamping
spurious cancels on idle rows.
* fix(table): seed dispatch overlay on Run; surface batch-enqueue failures as error
- useRunColumn.onSuccess invalidates the activeDispatches query so the
resolveCellExec queued overlay populates immediately for ahead-of-cursor
rows (scrolled-in / refetched), instead of waiting for the first dispatch
SSE. Targeted at activeDispatches only — the rows cache stays owned by
useTableEventStream.
- On batchEnqueueAndWait failure, dispatcherStep now flips the orphan
pre-stamps to a terminal `error` state and emits a cell SSE event, rather
than deleting them. The cursor still advances past the window, but the
dropped cells are now visible (Error pill) instead of silently empty, stay
out of the in-flight set, and re-run on the next manual run.
* fix(table): seed dispatch overlay on Run; surface batch-enqueue failures as error
- useRunColumn.onSuccess invalidates activeDispatches so the resolveCellExec
queued overlay populates immediately for ahead-of-cursor rows instead of
waiting for the first dispatch SSE. Rows cache stays owned by SSE.
- On batchEnqueueAndWait failure, dispatcherStep flips orphan pre-stamps to a
terminal error state (+ cell SSE) instead of deleting them, so the dropped
window is visible (Error pill) rather than silently empty and re-runs on the
next manual run.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
d55f40ce14 | fix(blocks): preserve agent block color (#4671) | ||
|
|
974a18dd61 |
improvement(media-blocks): new versions of image and video gen with latest models + fixes (#4667)
* improvement(media-blocks): new versions of image and video gen with latest models + fixes * respect versioning for icons * fix integration routes * address comments * address api mismatches * more ltx 2.3 durations * typing tightness |
||
|
|
e40c91588f |
fix(workflow-search): unclip block-name highlight shadow on the left (#4670)
The editor title h2 uses truncate (overflow:hidden) so the search highlight's -3px box-shadow was getting clipped on the left, exposing the mark's sharp edge. Replaces overflow:hidden with overflow:clip plus a 3px overflow-clip-margin so the shadow can bleed past the clip boundary without shifting the title text or breaking truncation. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
972ec5f216 | fix(branding): align auth and deploy UI colors (#4669) | ||
|
|
d7d58cec36 |
improvement(workflow-search): include block names in in-workflow search (#4668)
* improvement(workflow-search): include block names in in-workflow search Adds block names to the workflow search index alongside subblock content. Selecting a block-name match navigates to the block and highlights its title in the editor header with the same orange treatment used for subblock labels. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(panel-store): derive ActiveSearchTargetKind from WorkflowSearchTarget Replaces the hand-maintained literal union with a derived type so adding a new target kind in search-replace/types.ts automatically propagates here. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
6c755cbb59 |
feat(integrations): add Gong incident.io Railway and New Relic (#4663)
* feat(integrations): add Gong incident.io Railway and New Relic * fix(railway): preserve explicit empty variable values * fix(incidentio): fail on invalid workflow JSON * fix(new-relic): validate custom attributes JSON * fix(integrations): address incident workflow review fixes * chore(docs): apply lint formatting * chore: refresh integration docs and validation fixes * more * fix(integrations): address PR review comments * fix(gong): align list calls block validation |
||
|
|
df1e2ddc2e |
feat(azure-devops): block and trigger (#4664)
* azure devops logo on white * generated ADO tool docs * generated ADO tool docs * added ADO to registries * ADO workflow triggers * ADO workflow triggers * tool layer for ADO, checks passed and manual verified * ADO workflow triggers * block layer for ADO * ADO icon svg * generated docs for ADO triggers * committing the tests for azure devops tools and blocks * Update apps/sim/triggers/azure_devops/utils.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update apps/sim/tools/azure_devops/update_work_item.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update apps/sim/triggers/azure_devops/utils.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * comma syntax error patched * azure devops: validate-integration fixes + manual description - bgColor switched from white to Azure DevOps brand color #0078D4 (block + mdx) - WIQL query_work_items: hydrate ALL matched IDs by chunking through batches of 200 instead of silently truncating; check response.ok on the follow-up fetch and surface a clear error on 4xx/5xx; trim org/project; expose totalMatched in metadata so users can see pre-hydration count - Add MANUAL-CONTENT-START:intro section to the azure_devops.mdx docs page - Update unit tests for new chunking behavior and update-work-item validation Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * azure_devops: second-pass audit fixes + formatter cleanup - Add types barrel export to tools/azure_devops/index.ts - Normalize comment endpoint path casing (/workItems/ -> /workitems/) - Update test assertions to match normalized path - Biome formatter reflow across tools, triggers, registry, and docs icon Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * azure_devops: address PR review comments - Fix bgColor #FFFFFF -> #0078D4 in integrations.json and triggers/azure_devops.mdx - Bump File tool operationCount from 4 to 5 (Read, Fetch, Get, Write, Append) - Apply .trim() to org/project across all 15 remaining tools (consistency with query_work_items) - Fix Found ${data.count} -> Found ${data.count ?? items.length} fallback in list_builds, list_pipelines, list_pipeline_runs content strings Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * idemtpotency * azure_devops: address bugbot review comments - triggers/utils: match build.complete result case-insensitively, accept stopped/cancelled in addition to failed/canceled/partiallySucceeded so PascalCase and legacy Azure DevOps payloads aren't dropped - get_work_items_batch: chunk comma-separated IDs into 200-batch loops with proper status checks (was failing or returning incomplete data on >200 IDs) - Add tests for both behaviors Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * azure_devops: address additional bugbot comments - Block update_work_item now forwards areaPath; the Area Path subblock condition expanded to include update operation - get_build_timeline.failedRecords now also flags partiallySucceeded and succeededWithIssues, normalized case-insensitively. Output description and added a focused test Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * azure_devops: address more bugbot comments - Webhook provider extractIdempotencyId returns null when subscriptionId or notificationId is missing/empty, preventing the literal "azure_devops:undefined:undefined" key from collapsing unrelated deliveries into duplicates - Get Work Items Batch validates that at least one non-empty ID is supplied before issuing the API request, throwing a clear error instead of hitting an empty ids= query - Tests cover both behaviors Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * azure_devops: pin add_comment to documented api-version 7.0-preview.3 Microsoft's Add Comments docs only publish 7.0-preview.3 (the 7.2 view falls back to the 7.0 page). Get Comments stays on the documented 7.2-preview.4. Matches what's strictly in the Azure DevOps REST API reference rather than relying on undocumented version behavior. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Marcus Chandra <mzxchandra@gmail.com> Co-authored-by: mzxchandra <129460234+mzxchandra@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
49f70bc635 |
fix(docker): restore NEXT_PUBLIC_APP_URL build arg with dummy fallback (#4665)
* fix(docker): restore NEXT_PUBLIC_APP_URL build arg with dummy fallback getBaseUrl() in lib/core/utils/urls is evaluated at module load during next build's page-data collection and throws if NEXT_PUBLIC_APP_URL is unset. PR #4658 removed the build arg, breaking the Docker build at the "/_not-found" page-data collection step. Restore the dummy localhost fallback (mirroring DATABASE_URL). The CORS fix from #4658 is preserved: next.config.ts no longer reads NEXT_PUBLIC_APP_URL at build time, and no module-level expression captures getBaseUrl() — every caller invokes it at request time, where getEnv() reads the deployed container env. The dummy localhost value cannot leak into runtime CORS response headers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore(docker): trim verbose comment on build-time env args Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
6414b9381d |
improvement(cleanup): cleanup refs along in logs cleanup job (#4661)
* improvement(cleanup): cleanup refs along in logs cleanup job * address comments * cleanup code |
||
|
|
b98164fd3d |
feat(wiza): add Wiza integration for B2B prospect enrichment and search (#4662)
* feat(wiza): add Wiza integration for B2B prospect enrichment and search * fix(wiza): coerce reveal id to string, skip empty filters in prospect search * fix(wiza): throw on invalid JSON in advanced filter fields instead of silently dropping |
||
|
|
ef14b2b580 |
fix(security): remove localhost CORS origin, consolidate CORS in proxy (#4658)
* fix(security): remove localhost CORS origin, consolidate CORS in proxy Move all /api/* CORS handling from next.config.ts to proxy.ts so the runtime can resolve allowed origin per-request instead of baking it at build time (which produced "Access-Control-Allow-Origin: http://localhost:3000" with credentials:true in production). - proxy.ts: per-route CORS policy table covering auth, MCP, form, and workflow execute endpoints; OPTIONS preflight short-circuit; Vary: Origin when origin is not '*'; form routes defer to route handler's addCorsHeaders to avoid double-setting - next.config.ts: drop all /api/* Access-Control-Allow-* headers; keep COEP/COOP/CSP - deployment.ts: addCorsHeaders sets Vary: Origin alongside reflected Allow-Origin - Dockerfile: drop NEXT_PUBLIC_APP_URL build placeholder (Zod has skipValidation:true; build path doesn't read it) - Remove 8 dead OPTIONS handlers and their preflight tests now that the proxy handles preflight uniformly * refactor(cors): consolidate API CORS into proxy as single source of truth Move CORS for /api/chat/* and /api/form/* into the proxy policy table with reflected-origin + credentials:false, and delete the per-route addCorsHeaders helper. Routes no longer set CORS headers — the proxy is the only writer. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(cors): convert proxy CORS policy chain to a rule table + add tests Replace the if/else chain in resolveApiCorsPolicy with a CORS_RULES table so each route's policy lives in one place and is trivially scannable. Add proxy.test.ts covering each rule and the wildcard-with-credentials invariant. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(cors): scope embed CORS rule to /api/{chat,form}/[identifier] only The embed policy (reflected origin, credentials:false) was matching workspace-internal session-authed routes — /api/chat, /api/chat/manage/*, /api/chat/validate, and the form equivalents — which need the default credentialed policy. Tighten the matcher to the embed paths only and add tests covering the exclusion. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(cors): replace embed-path regex with explicit segment check The regex form `^/api/(chat|form)/(?!manage|validate)[^/]+(/(otp|sso))?$` was opaque on review and would silently exclude any future identifier subroute outside the hard-coded (otp|sso) group from the embed policy. Replace it with an imperative segment check and a named EMBED_RESERVED_SEGMENTS Set, so the policy boundary is visible at the top of the function and adding a reserved subpath is a one-line diff. Add a test asserting that future identifier subroutes also get the embed policy. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(cors): allow PUT in embed CORS policy for OTP verification Both /api/chat/[identifier]/otp and /api/form/[identifier]/otp export PUT for OTP code verification. The embed policy advertised only GET/POST/OPTIONS, so cross-origin embed clients failed preflight on verify. Add PUT and assert it in the embed policy test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
3930485dff | feat(models): add gemini 3.5 flash (#4660) | ||
|
|
279010a2e7 |
improvement(execution): memory usage for aggregated results (#4650)
* improvement(execution): memory usage for aggregated results * progress * address comments * loop/parallel results compaction * address comment * remove build files, harden edge cases * remove hotpath serialiazation * display change to make use of only preview * materialize refs before sending in response block * preserve exact large-value access through workflow materialization * address comments * progress * fix notif error + sync manifest undefined exit * fix streaming ref materialization * fix tests |
||
|
|
6827be7f43 |
feat(google_docs): opt-in Markdown formatting for create operation (#4656)
* feat(google_docs): opt-in Markdown formatting for create operation * fix(google_docs): harden multipart boundary handoff and align postProcess guard |
||
|
|
a0d9e4dc90 |
fix(tables): type-aware SQL casts for range filters on date columns (#4657)
* fix(tables): type-aware SQL casts for range filters on date columns * improvement(table): tighten filter-cast types & workspace guards - Drop redundant tableId/workspaceId from BulkUpdateData and BulkDeleteData; service uses table.id / table.workspaceId so column metadata and DB scope can't drift apart. - Add missing workspace-id guards to copilot user-table cases (insert_row, batch_insert_rows, update_row, batch_update_rows, rename); collapse duplicated rename check. - Add service-level integration tests that buildFilterClause/buildSortClause receive table.schema.columns from queryRows, updateRowsByFilter, deleteRowsByFilter. * improvement(table): cast jsonb date filters/sorts to timestamptz ::timestamp strips timezone offsets from ISO strings, making comparisons depend on the server TimeZone setting. ::timestamptz preserves the offset so chronological comparisons are correct regardless of server config. * improvement(table): correct JSDoc examples for required columns arg * improvement(table): validate range operator value types at SQL builder |
||
|
|
0c1167d76b |
improvement(workspace): fix resource table column proportions and toast stacking (#4655)
* improvement(workspace): fix resource table column proportions and toast stacking * fix(resource): restore scrollbar-gutter stable on table scroll container * fix(resource): remove scrollbar-gutter stable — single-table layout doesn't need it * fixed files cols * fix(findymail): add required enabled field to wandConfig entries * fix(findymail): remove optional from block outputs — not valid on BlockConfig output type * fixes * fix(files): use folderSizeMap for sort value so size sort matches display * files ref |
||
|
|
f3cf8fc55d |
feat(findymail): add Findymail B2B contact data integration (#4654)
* feat(findymail): add Findymail B2B contact data integration Adds 11 tools covering verified email lookup (by name, LinkedIn, domain roles), email verification, reverse email lookup with profile enrichment, company info, employee discovery, phone lookup, technology stack detection, and credit checks. Single API-key block with operation dropdown, gradient-rendered icon, and generated docs. * fix(findymail): handle HTTP errors and surface last_detected_at - All 11 tools now check response.ok and return success:false with the API error message on non-2xx responses - search_technologies now maps last_detected_at to match lookup_technologies and the shared output schema - Restore file_v3 in docs icon-mapping (translated docs still reference it) * improvement(findymail): exclude operation from params transform Match the convention used by enrich/apify/box/calendly — destructure out operation before forwarding the rest to the tool call, so the operation key doesn't leak into the tool payload. |
||
|
|
b276672867 |
feat(prospeo): add Prospeo integration for B2B contact enrichment and search (#4653)
* feat(prospeo): add Prospeo integration for B2B contact enrichment and search Adds 8 operations: enrich person/company, bulk enrich person/company, search person/company, search suggestions, and account information. Uses X-KEY header auth. * refactor(prospeo): extract shared parse helpers into utils.ts |
||
|
|
cf146931dd |
improvement(memory): replace unbounded server caches with lru-cache to fix heap growth (#4652)
* fix(memory): prune toolSchemaCache and semaphores to prevent heap growth toolSchemaCache (lib/copilot/chat/payload.ts): module-level Map keyed by userId:workspaceId never deleted expired entries, only checked TTL on read. With 100K+ unique user/workspace pairs each holding 50-200KB of tool schemas, this was the primary driver of the 24MB -> 25GB heap growth observed in CloudWatch. Add a setInterval sweep every 30s (matching the TTL) with .unref() so it does not prevent graceful shutdown. semaphores (lib/core/async-jobs/backends/database.ts): acquireSlot created Semaphore entries that releaseSlot never deleted. With per-execution UUID keys (e.g. scheduleJobId), each scheduled workflow run would add a permanent entry. Store the concurrency limit on the Semaphore struct and delete the entry from the Map when all slots are free and no waiters remain. validatorCache (lib/copilot/tools/server/generated-schema.ts): validated as bounded (93 tools x 2 schema kinds = 186 max entries, ~2-9MB). No fix needed. isolated-vm nativeContexts: validated as deferred GC, self-healed by worker rotation at MAX_EXECUTIONS_PER_WORKER=200. externalMB spikes trace to concurrent isolate heaps at peak load (128MB limit x active isolates), not a reference leak. No fix needed. * fix(memory): prune effectiveEnvCache and instrument cache sizes in telemetry effectiveEnvCache (lib/environment/utils.ts): same unbounded accumulation pattern as toolSchemaCache — module-level Map keyed by userId:workspaceId with a 15s TTL that is only checked on read, never proactively evicted. Adds a periodic sweep matching the TTL interval with .unref(). cache-registry (lib/monitoring/cache-registry.ts): lightweight registry so modules can expose their cache sizes to telemetry without coupling. toolSchemaCache and effectiveEnvCache both register on module load. memory-telemetry: emits cacheSizes in every Memory snapshot log so CloudWatch can confirm the caches stay bounded post-deploy. * improvement(memory): replace manual TTL Maps with lru-cache for toolSchemaCache and effectiveEnvCache Replaces the homegrown Map + setInterval sweep pattern with LRUCache from the lru-cache npm package, which is the standard Node.js solution for bounded in-process caching with TTL. Changes per cache: - Removes manual ToolSchemaCacheEntry / EffectiveEnvCacheEntry types - Removes setInterval sweep timers (and the .unref() boilerplate) - Removes the two-phase promise->value entry update inside the IIFE - Stores Promise<T> directly — in-flight and resolved states share one type - max: 200 (toolSchemaCache) / max: 500 (effectiveEnvCache) as hard ceilings - TTL behaviour and concurrent-request deduplication are preserved exactly - cache-registry .size reporting works unchanged via lru-cache's .size prop * fix(memory): remove redundant waiters guard in releaseSlot |
||
|
|
268fa0e97e |
fix(knowledge): preserve scroll position when toggling tokenizer in chunk viewer (#4643)
* fix(knowledge): preserve scroll position when toggling tokenizer in chunk viewer * fix(knowledge): skip scroll restore on initial mount of chunk editor * chore(dev): add dev:clean script to purge Turbopack cache |
||
|
|
3979476432 | improvement(workspace): allocate more space to name column in resource tables (#4645) | ||
|
|
42bbb8aa49 |
improvement(mothership): abort path race preventing persistence (#4647)
* improvement(mothership): abort path race preventing persistence * address comments * address bugbot comment |
||
|
|
4dc78cb82b |
improvement(redis-cleanup): schedule, async workflow, hitl base64 cache cleanup (#4646)
* improvement(redis-cleanup): schedule, async workflow, hitl bae64 cache cleanup * address comments |
||
|
|
08eeecbebe |
fix(security): KB fileUrl LFI, MCP/Agiloft SSRF pinning, form OTP, KB authz (#4639)
* fix(security): KB fileUrl LFI, MCP/Agiloft SSRF pinning, form OTP, KB authz * fix(otp): don't leak caught error.message; fail-closed on DB retry exhaust - Chat/form OTP routes: replace `error.message || fallback` with generic `Failed to process request` in 500 responses (logger still captures detail). - otp.ts incrementOTPAttempts DB path: on MAX_RETRIES exhaustion, delete the verification row and return `'locked'` instead of trusting a possibly- undercounted final read. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(mcp): use undici fetch directly in pinned-fetch for typed dispatcher Replace `globalThis.fetch` + double-cast with `undici.fetch` so the `dispatcher` option is part of the real type contract. This guarantees pinning won't silently break if a future runtime swaps the underlying fetch implementation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(build): keep agiloft/grafana tool configs client-safe Tool config files are statically reachable from the client bundle (via tools/registry.ts → tools/{service}/index.ts). Importing `@/lib/core/security/input-validation.server` from these files pulled `node:dns/promises` into the Turbopack client bundle and broke the build. Split agiloft utils into client-safe (`utils.ts`, plain fetch + sync `validateExternalUrl`) and server-only (`utils.server.ts`, DNS-pinned variants). Routes that need TOCTOU protection import the pinned helpers; the executor-side tool path falls back to sync URL validation (matches the supabase precedent and pre-PR baseline). Grafana update tools likewise switch from `secureFetchWithValidation` (server-only) to inline sync `validateExternalUrl` + plain fetch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(knowledge): case-insensitive scheme checks for fileUrl Boundary schema accepted uppercase schemes (e.g. HTTPS://, DATA:) via the case-insensitive http regex, but the processor's case-sensitive startsWith('data:') / startsWith('http') / startsWith('https://') checks rejected them with a confusing "Unsupported fileUrl scheme" error. Aligns processor checks to the schema using case-insensitive regex per RFC 3986 §3.1. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(mcp): annotate undici/DOM type-bridge double-casts in pinned-fetch Strict audit was failing on two new `as unknown as` casts in pinned-fetch.ts. They bridge DOM `RequestInit`/`Response` ↔ undici equivalents (structurally compatible at runtime since Node's global fetch is undici) and are required to satisfy the FetchLike contract. Annotate so they count as documented exemptions instead of new violations. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
fd12137c28 | improvement(copilot): drop unused columns from mothership chat detail reads (#4640) | ||
|
|
4945d55671 |
fix(redis): apply TLS SNI override to pub/sub clients (#4638)
* fix(redis): apply TLS SNI override to pub/sub clients too Pub/sub clients in lib/events/pubsub.ts build their own ioredis instances directly via new Redis(redisUrl, ...) because pub/sub needs dedicated connections (can't multiplex on the shared client from getRedisClient). That path skipped the resolveTlsOptions helper added for trigger.dev's PrivateLink VPCE IP, so every pub/sub channel hit 'Hostname/IP does not match certificate's altnames' on connect. Export the helper as resolveRedisTlsOptions and use it from pubsub.ts. * refactor(redis): share connection defaults via one helper Extract keepAlive/connectTimeout/enableOfflineQueue + TLS SNI into a single getRedisConnectionDefaults helper. Main client and pub/sub clients both spread it; caller-specific retry/timeout policy stays per-caller (pub/sub still needs maxRetriesPerRequest: null and a different retry strategy for SUBSCRIBE). * fix(pubsub): surface TLS config errors instead of silently degrading resolveRedisTlsOptions (via getRedisConnectionDefaults) throws if REDIS_TLS_SERVERNAME is missing for an IP-based rediss:// URL. Calling it inside the constructor let createPubSubChannel's try/catch swallow the error and fall back to in-process EventEmitter — silent cross-replica pub/sub breakage in prod. Resolve defaults before the try so config errors propagate; only catch genuine runtime construction failures. |
||
|
|
bd9e692b91 |
feat(redis): TLS SNI override for IP-based REDIS_URL + zod schema fixes (#4635)
* feat(redis): allow TLS SNI override for IP-based REDIS_URL
When trigger.dev's hosted workers reach our ElastiCache via PrivateLink,
their REDIS_URL contains the VPCE-assigned IP, not a DNS name. Default
ioredis TLS verification fails because the ElastiCache cert is issued for
the cluster's DNS, not the IP.
Add REDIS_TLS_SERVERNAME env var; when REDIS_URL is rediss:// + IP host,
pass `tls: { servername }` to ioredis so cert hostname verification
matches against the DNS name instead. Throws at client construction if
REDIS_TLS_SERVERNAME is unset in this scenario (fail fast — no silent
TLS bypass).
No-op for in-VPC connections (DNS host), so the always-on Sim app keeps
using default verification.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(confluence-schemas): expose extendable bases before .superRefine
confluenceCommentScopedSchema and confluenceBlogPostScopedSchema were
built with .extend(...).superRefine(...). superRefine returns a
ZodEffects which has no .extend method, so the three downstream
.extend() calls (confluenceUpdateCommentBodySchema,
confluenceGetBlogPostBodySchema, confluenceUpdateBlogPostBodySchema)
threw at module-init time.
Next.js lazy-loads route code per-request and never executed this
top-level chain, hiding the issue. Trigger.dev's bundler eagerly
evaluates all task-reachable modules at startup, which is why the
trigger.dev deploy surfaced it as "confluenceCommentScopedSchema.extend
is not a function" across every background task that transitively
imports this file.
Fix: introduce un-superRefined base schemas and use them as the .extend
target downstream; apply superRefine after each .extend so validation
behavior is preserved for every consumer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(storage-transfer): use z.string().url() for Zod 3 compat
z.url() is Zod 4 top-level syntax. The hoisted node_modules/zod
resolves to v3.25.76 (despite apps/sim/package.json declaring 4.3.6 —
a workspace resolution conflict), so z.url is undefined at runtime.
Trigger.dev's bundler eagerly evaluates all task-reachable modules at
startup and hits this with `external_exports.url is not a function`.
Next.js dev only evaluates routes per-request so the call site never
fires.
Quick fix: revert to the chained .string().url() form which works on
both Zod 3 and Zod 4 (deprecated in 4 but still supported). The
underlying version-resolution conflict is a separate cleanup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(mongodb-schemas): expose extendable base before .refine
mongoConnectionBodySchema was built with z.object(...).refine(...). Five
downstream schemas (mongodbQueryBodySchema, mongodbExecuteBodySchema,
mongodbInsertBodySchema, mongodbUpdateBodySchema, mongodbDeleteBodySchema)
.extend() that result, which threw at module-init in the trigger.dev
bundle (same root cause as the confluence and storage-transfer fixes:
.refine returns ZodEffects with no .extend method, and the resolved
zod is v3 even though package.json declares v4).
Fix: keep the un-refined mongoConnectionBaseSchema for downstream
.extend() targets. The pairing-validation refine isn't reattached
because the downstream extensions were never actually evaluating it
(module init threw before they could).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(redis,mongodb): address PR review comments
- redis.ts: move resolveTlsOptions call outside the try/catch in
getRedisClient so config errors surface instead of being swallowed
into a silent null return.
- mongodb.ts: re-attach mongoUsernamePasswordPaired .refine after each
of the five downstream .extend()s. Mirrors the confluence pattern
and restores the pairing constraint that the original chain dropped.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
67e18f747d | fix(migrations): remove duplicate column add (#4632) | ||
|
|
ff23546f30 |
fix(workflows): exclude block locked from diff detection (#4631)
Toggling a block's locked state is UI metadata and should not register as a workflow drift/diff. Strip locked from hasBlockChanged, computeFieldDiff, the compare.ts blockFields list, and from extractBlockFieldsForComparison so it's also excluded from the normalized stringify-based block equality check used by drift detection and hashing. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
3712d1e2df |
feat(mship): make mship block stream output (#4626)
* Mship block stream * Improvements * Fixes * Fix stream * Fix * Fix |
||
|
|
f8ae249e7d |
improvement(executor): faster, more responsive workflow cancellation (#4630)
* improvement(executor): faster, more responsive workflow cancellation * fix(executor): publish cancellation event on Redis write failure * fix(tests): migrate handler test assertions to executeTool options object * chore(tests): rename stale 'cancellation check interval' test after polling removal |
||
|
|
fffb87901d |
feat(wait): Async toggle, chained-wait resume fix, execution status API (#4514)
* fix(wait): poll partially_resumed rows so chained waits resume The chained-pause flow leaves a row in 'partially_resumed' status (wait1 done, wait2 still waiting). The poll's WHERE filter only matched 'paused', so wait2 was never picked up. Include 'partially_resumed' in the filter. * feat(wait): make in-process threshold env-overridable for local testing Adds WAIT_INPROCESS_MAX_MS env var (default 300000ms = 5 min). Lower it locally (e.g. 5000) to exercise the suspend/cron-resume path with short waits. * feat(wait): add Suspend Workflow toggle, restore 5-min in-process default * fix(wait): address bot review — setNextResumeAt + suspend unit default - setNextResumeAt now matches paused OR partially_resumed; otherwise the cron poller can't null nextResumeAt after dispatching a chained-wait row, so it keeps reappearing in every poll batch until execution ends (flagged by both greptile and bugbot) - Suspend mode now defaults missing timeUnitLong to 'minutes' instead of falling back to 'seconds' and immediately erroring (flagged by bugbot) * improvement(wait): hint the wait-amount cap on the input Restores the pre-#4331 description on the Wait Amount field so the limit is visible before submit instead of only at runtime. Mentions both the 5 min default and the 30 day cap with Suspend Workflow. * refactor(wait): rename Suspend Workflow toggle to Async * fix(wait): reword cap errors to say 'async mode' * feat(workflows): add GET /workflows/[id]/executions/[executionId] status endpoint Normalized status (pending|running|paused|completed|failed|cancelled) across workflowExecutionLogs and pausedExecutions in a single response. Surfaces paused-state details (resumeAt, pauseKind, blockedOnBlockId) when a row exists in pausedExecutions, and the error string for failed runs. finalOutput is opt-in via ?includeOutput=true. * feat(workflows): support ?selectedOutputs= on execution status endpoint Returns per-block outputs filtered by selectedOutputs paths (same shape as the execute endpoint). Reads from executionData.traceSpans, walks children recursively, and resolves dot-paths into each block's output. Bare blockId returns the full output. * fix(wait): drop dead tooltip prop on Async switch Switch sub-blocks return null from renderLabel (sub-block.tsx:238), so the tooltip never reached the user. The trade-off explanation already lives in longDescription and bestPractices. Flagged by bugbot. * docs(api): document GET /workflows/[id]/executions/[executionId] Adds the WorkflowExecutionStatus schema and the getWorkflowExecution operation to the OpenAPI spec, including completed/paused/failed response examples and the includeOutput + selectedOutputs query params. Registers the page in the Workflows section of the API reference. * docs(api): tighten getWorkflowExecution descriptions |
||
|
|
f76e8e6dcc |
improvement(copilot): trim copilot_chats reads to lean projections (#4629)
* improvement(copilot): trim copilot_chats reads to lean projections * fix(copilot): exercise idempotent-delete guard via the lean auth mock |
||
|
|
674dd8d91f |
fix(mcp): map validation and conflict orchestration errors to 400/409 (#4628)
* fix(mcp): map validation and conflict orchestration errors to 400/409 * fix(mcp): migrate workflow-server routes to mcpOrchestrationStatus |
||
|
|
93f7be4097 |
improvement(redis): strip idempotency body and cap mothership stream zsets (#4625)
* improvement(redis): strip idempotency body and cap mothership stream zsets * chore(redis): trim verbose comments on idempotency body-strip * test(buffer): pin exact ZREMRANGEBYRANK stop arg Pinning -5_001 (= -(DEFAULT_EVENT_LIMIT) - 1) so the off-by-one boundary is directly validated; expect.any(Number) would have passed a wrong formula like -eventLimit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
8d7bbbc670 |
chore(utils): migrate to shared random/ID utilities and add enforcement linting (#4623)
* chore(utils): migrate to shared random/ID utilities and add enforcement linting - Replace all Math.random(), crypto.randomUUID(), crypto.randomBytes(), nanoid, and uuid usages with shared @sim/utils/random and @sim/utils/id helpers across 72 files - Add new @sim/utils exports: deepClone, omit, filterUndefined (object), truncate (string), backoffWithJitter, parseRetryAfter (retry), getErrorMessage (errors) - Sweep all getErrorMessage, sleep, deepClone callsites across 500+ files to use shared utilities - Add Biome noRestrictedImports rule to catch nanoid, uuid, and crypto named imports at lint time - Add scripts/check-utils-enforcement.ts to catch Math.random and crypto.* global property access - Add check:utils script to package.json * chore(utils): replace deepClone wrapper with structuredClone built-in deepClone() was a one-line wrapper around structuredClone(), which is universally available in Node 17+ and all modern browsers. Removing the abstraction reduces indirection and means contributors don't need to learn a project-specific name for a well-known built-in. - Remove deepClone from packages/utils/src/object.ts and index.ts - Replace all 17 call sites with structuredClone() directly - Update check:utils script suggestion text - Update CLAUDE.md and global.md docs * fix(utils): add missing biome noRestrictedImports rule and correct truncate docs - Add noRestrictedImports to biome.json under style — bans nanoid and uuid package imports at lint time (crypto.randomUUID/randomBytes are caught by the check:utils grep script which handles global property access) - Correct truncate() TSDoc and parameter name: sliceLength makes it clear that total output length is sliceLength + suffix.length, matching the behavior all callers were already written to expect * fix(utils): add missing getErrorMessage imports at 4 call sites The sweep agents added getErrorMessage calls without the corresponding import in 4 files, causing test failures. Added the missing imports. * fix(utils): fix build errors from getErrorMessage sweep and retry.ts Turbopack issue - Fix retry.ts cross-file import: Turbopack cannot resolve './random.js' for internal package imports; inline the jitter crypto call directly - Add missing getErrorMessage imports to 32 files where the sweep added calls without the corresponding import (caught by type-check and test runs) - Remove accidental getErrorMessage import from crowdstrike/query/route.ts which has its own domain-specific getErrorMessage for parsing CrowdStrike's JSON error format - Fix use-sub-block-value.ts type error from structuredClone narrowing: add 'as T' cast at emitValue callsite (safe — valueCopy is always a structural copy of newValue) * fix(tools): use toError in crowdstrike catch block instead of local getErrorMessage The catch block was calling the local getErrorMessage function which parses CrowdStrike API JSON responses, not JavaScript Error objects. Use toError(error).message to correctly extract the message from a caught value in this context. |
||
|
|
c403fafd11 |
fix(cloudwatch): use PutAlarmMuteRule for mute/unmute with duration window (#4621)
* fix(cloudwatch): use PutAlarmMuteRule for mute/unmute with duration window * fix(cloudwatch): drop AWS StartDate to avoid race with at() trigger |
||
|
|
0dc1611f39 |
improvement(providers): align attachment dispatch to vendor SDK types (#4619)
* improvement(providers): align attachment dispatch to vendor SDK types Post-merge audit of #4610 surfaced three follow-ups: 1. xAI Grok vision was blocked. Grok runs through the OpenAI-compatible chat-completions endpoint, so removing xAI from UNSUPPORTED_FILE_PROVIDERS and routing it through the image-only branch restores image attachments on vision models. 2. Azure OpenAI chat-completions deployments blocked any file attachment. Added a per-message image_url parts path; documents still require the Responses API endpoint and throw a clear, actionable error. 3. Wire shapes were loosely typed (Record<string, unknown> arrays). Replaced with `satisfies` clauses against each vendor SDK union at every push site: OpenAI Responses/Chat, Anthropic ContentBlockParam, Gemini Part, Bedrock ContentBlock members. AnthropicImageMediaType now derives from Base64ImageSource['media_type'] so it tracks SDK updates. Also collapsed the validation cascade into an exhaustive switch with `never` enforcement, and dropped the redundant per-provider formatMessagesForProvider call from xai/index.ts (providers/index.ts already runs the dispatcher centrally). * fix(providers): restore getProviderAttachmentMaxBytes export and xAI message dispatch - Restore `getProviderAttachmentMaxBytes` — still consumed by agent-handler.ts for per-provider attachment size limits in file hydration - Restore `formatMessagesForProvider(allMessages, 'xai')` — providers/index.ts does NOT dispatch centrally on this branch; each OpenAI-compat provider formats its own messages. Without it, xAI Grok vision drops image attachments * fix(providers): tighten ResponsesInputItem content type to SDK ResponseInputContent Build fix: buildOpenAIMessageContent returns ResponseInputContent[] which isn't assignable to Record<string, unknown>[] (ResponseInputText lacks an index signature). Align the type to the SDK shape. |
||
|
|
cb9c2d5452 |
improvement(files): validations (#4620)
* Fix * Fixes |
||
|
|
a64b338236 |
fix(files): fixed resource spacing on files directories pages (#4618)
* fix(files): fixed resource spacing on files directories pages * fix(build): align turbo schema version Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
d3d8f9c861 |
fix(logs,workspace): prevent cancelled status overwrite on race and move impersonation banner (#4617)
- Guard completeWithError against overwriting a cancelled execution status — cancel route writes cancelled to DB optimistically, but a block error racing the 500ms Redis check could finalize with failed before the engine detects cancellation - Add tests covering the guard: cancelled DB status skips the write, non-cancelled proceeds normally, DB failure falls through to cost-only fallback, and subsequent attempts are deduped after guard marks session complete - Move ImpersonationBanner from workspace root into components/ folder |
||
|
|
c9118e775b |
feat(files): folders, multiselect, vfs update (#4572)
* 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 * feat(files): folders + vfs update * address comments * address comments * cleanup unnused code * address comments * perf improvements * address next set * cycle detect * error handling * path improvements * cleanup, best practices * react query best practices: targeted invalidation, optimistic updates, key factory hierarchy - Add workspaceLists(workspaceId) intermediate key level to both workspaceFilesKeys and workspaceFileFolderKeys so invalidation targets only the affected workspace instead of all workspaces - Replace all lists() invalidation calls with workspaceLists(workspaceId) across every mutation (upload, rename, delete, restore, update content, folder mutations) - Add optimistic updates to useRenameWorkspaceFile and useUpdateWorkspaceFileFolder with onMutate snapshot, onError rollback, onSettled reconciliation - Move storage key into the content() factory as optional param so query keys are always built through the factory (useWorkspaceFileContent, useWorkspaceFileBinary) - Fix AnimatePresence wrapping in FilesActionBar so exit animation fires on deselect - Fix ResourceColGroup to use percentage weights instead of pixel widths to prevent horizontal scroll on narrow viewports * add shift-click range selection and selection-aware context menu for files - Extend SelectableConfig.onSelectRow with optional shiftKey param; DataRow captures shiftKey before onCheckedChange fires via a ref so the Radix Checkbox interaction chain stays intact - Implement shift-click range selection in files.tsx using lastSelectedIndexRef; tracks last-selected index in visibleRowIds to compute the range - Reset lastSelectedIndexRef on deselect and select-all - Add selectedCount prop to FileRowContextMenu; hide Open and Rename when multiple items are selected, show "Delete N items" / "Download N items" labels in multi-select mode * add Move submenu to file context menu and fix shift-click anchor update - Add nested Move submenu to FileRowContextMenu using DropdownMenuSub/SubTrigger/SubContent; shows available folders filtered by selection, converts '__root__' -> null for moving to the root level - Add handleContextMenuMove in files.tsx that calls moveItems.mutateAsync directly (no modal) and clears selection on success - Fix shift-click range selection: update lastSelectedIndexRef after range select so chained shift-clicks extend from the new anchor point correctly * fix move submenu: use folder names with tree-ordered indentation instead of stale paths - Compute folder depth from parentId chain client-side (avoids stale server-computed path field) - Tree-order folders so parents appear before their children, sorted by sortOrder then name - Show folder.name instead of folder.path so optimistic renames are reflected immediately - Indent each folder by depth * 12px in the submenu so po/shit renders as 'shit' indented under 'po' - MoveOption gains optional depth field; contextMenuMoveOptions is a separate memo from moveFolderOptions (modal keeps its existing path-label behavior) * fix shift-click anchor drift and remove dead stopPropagation constant - Remove dead stopPropagation const in resource.tsx (replaced by handleSelectRowClick) - Reset lastSelectedIndexRef when visibleRowIds changes so search/filter/folder navigation doesn't leave a stale anchor that produces wrong ranges on the next shift-click - Update lastSelectedIndexRef in handleRowContextMenu when right-clicking resets selection to a single item, so the anchor matches the newly-selected row - Add visibleRowIds to handleRowContextMenu deps (now reads it to compute anchor index) - Remove moveItems.mutateAsync from handleContextMenuMove deps per project convention (.mutateAsync is stable in TanStack v5) * complete workspace files feature: audit logs, posthog events, folder restore, empty state, keyboard shortcuts, storage indicator, breadcrumb rename - Audit + PostHog: wire file_renamed, file_deleted, file_moved, file_bulk_deleted, folder_created, folder_renamed, folder_deleted, folder_moved events to all file/folder API routes - Add AuditAction.FOLDER_UPDATED, FILE_MOVED, FOLDER_MOVED to audit types - Folder restore: server function, contract, API route (POST /files/folders/[folderId]/restore), hook (useRestoreWorkspaceFileFolder), Recently Deleted integration with new File Folders tab - Empty state: contextual emptyMessage passed to <Resource> based on search/filters/folder context - Keyboard shortcuts: Delete/Backspace deletes selection, Escape deselects, Cmd+A selects all (list view only, input-aware guard) - Storage indicator: useStorageInfo drives compact "used / limit" display in file list header via leadingActions - Breadcrumb rename: current folder breadcrumb gains Rename dropdown + inline editing via breadcrumbRename (useInlineRename) - Resource: thread leadingActions prop from ResourceProps to ResourceHeader * cleanup: accessibility, emcn design tokens, react best practices across workspace UI - Add sr-only ModalDescription to dialogs/modals for accessibility - Replace hardcoded colors and z-indices with design token CSS variables - Apply emcn design review fixes across tables, knowledge, logs, settings, workflows * fix audit and posthog: FOLDER_RESTORED action on restore, fire folder_moved event separately from file_moved * sidebar: add Files section with nested folder tree; polish move UX and cleanup - Files section in sidebar shows folder/file tree with expand/collapse, matching Workflows section structure; collapsed sidebar shows flyout menu - Move action bar now uses nested DropdownMenuSub tree instead of flat modal - Context menu and action bar share renderMoveOption from move-options.tsx - FolderInput added to emcn icons barrel; all FolderInput imports migrated - Drag ghost uses CSS vars (--border, --shadow-medium, --z-toast) - Selection pruning converted from useEffect to render-time comparison - Keyboard listener stabilized with handleBulkDeleteRef pattern - toError() used consistently in restore and move route handlers * remove Files section from sidebar * restore Files nav item in sidebar workspace section * fix infinite re-render on files page - revert selection pruning to useEffect * add filefolder resource type for ingesting workspace file folders * export filefolder tree types; add toast feedback for file/folder mutations * regenerate migration as 0208 after rebase onto staging * add workspaceFileFolder to schema mock * add FILE_MOVED, FOLDER_MOVED, FOLDER_UPDATED to audit mock * add filefolder ChatContext kind and wire through schema and resolver * add filefolder to AgentContextType * add filefolder to chat context kind registry; fix resolver to use workspaceFiles table * add .deepsec to gitignore * cleanup: effect, emcn tokens, mutation error handling - Replace selection-pruning useEffect with inline state adjustment during render - Fix drag overlay using invalid --accent HSL token → --brand-secondary; z-50 → z-[var(--z-dropdown)] - Move static inline styles on context menu trigger div to className - Add missing onError toast to useUpdateWorkspaceFileFolder, useRestoreWorkspaceFileFolder, useRestoreWorkspaceFile * lint * fix: remove duplicate handleCopilotStopGeneration from rebase * feat(copilot): folder-aware file context in WORKSPACE.md * feat(copilot): add move operation to file manage API * fix(files): make targetFolder optional in move file contract * perf(files): parallelize buffer fetches, fix N+1 folder queries, stabilize drag useMemo - download route: fan out all fetchWorkspaceFileBuffer calls with Promise.all before zip assembly so 100 files resolve in one round-trip instead of sequentially - getWorkspaceFileFolder: replace per-ancestor SELECTs with a single workspace-wide folder load + buildWorkspaceFileFolderPathMap, making depth irrelevant to query count - ensureWorkspaceFileFolderPath: pre-load all workspace folders in one SELECT before the segment loop; resolve existing segments from an in-memory map; only hit the DB to CREATE missing segments; conflict retry path preserved and also updates the map - files.tsx rowDragDropConfig: move activeDropTargetId into a ref so the useMemo does not recompute on every drag-over event * fix(files): remove files/ path stripping, fix stale path in optimistic update - splitWorkspaceFilePath: remove the unconditional .replace(/^files\//, '') that clobbered paths for files inside a folder literally named "files" - useUpdateWorkspaceFileFolder: when a name update is in flight, recompute the path field for the renamed folder (replace last segment) and propagate the new prefix to all descendant folders so breadcrumbs stay correct during the optimistic window * fix(files): revert broken ref opt, clean 409 on restore, null parentId on orphaned restore - files.tsx: revert the activeDropTargetId ref optimization — the ref doesn't trigger re-renders so the drop-target highlight never updated during drag; activeDropTargetId is back in state and in the rowDragDropConfig deps - restore/route.ts: catch Postgres 23505 unique-constraint violation and return a clean 409 instead of leaking the raw error as 400 - restoreWorkspaceFileFolder: check if the parent folder is still archived before restoring; if it is, restore to root (parentId: null) so the folder is never orphaned under an archived parent * feat(search): show folder path for files in cmd-k modal, strip extraneous comments - FileItem interface with folderPath?: string[] added to search modal utils - MemoizedFileItem component renders folder breadcrumb identically to MemoizedWorkflowItem — truncated path segments on the right with / separators - FilesGroup rewritten as a dedicated memo component (was createIconGroup factory) so it accepts FileItem[] and includes folderPath segments in the search value - searchModalFiles in sidebar splits f.folderPath string into string[] segments - search-modal.tsx typed to FileItem and includes folderPath in filterAndSort - Remove self-explanatory "Phase 1" section label from download route - Remove redundant TSDoc on the unique index in db schema * fix(workspace-files): audit fixes — transaction, status codes, contract refinements, guards * fix(vfs): pass folderPath separately so buildWorkspaceMd groups files correctly * fix(types): narrow unknown fileInput with Record cast after object guard * fix(routes): replace instanceof Error with toError() across new workspace file routes * improvement(files): cleanup pass — remove unnecessary useCallbacks, consolidate emcn icon imports - Remove useCallback from 5 drag-event handlers in DataRow (passed to native <tr> elements, no observer) - Remove stable useCallback fns from 3 useMemo deps arrays in files.tsx (editingId/editValue remain) - Merge all @/components/emcn/icons subpath imports into barrel (files.tsx, action-bar, file-row-context-menu) * fix(files): apply activeSort to folders, reject drop onto current parent folder - visibleFolders now respects activeSort column (name/updated/created) and direction so folder ordering stays consistent with file ordering - isInvalidDropTarget now returns true when all dragged items are already direct children of the target folder, preventing a no-op move mutation * fix breadcrumb * add new tools to rename, create, delete folders * move more ui actions into orchestration dir * address comments * fix params * fix tests * address comments * improve error codes * address comments * address more nits * fix mcp server error code --------- Co-authored-by: Theodore Li <theodoreqili@gmail.com> Co-authored-by: waleed <walif6@gmail.com> |